Async вызывает обходной путь - PullRequest
       3

Async вызывает обходной путь

0 голосов
/ 09 сентября 2018

У меня есть JS-скрипт для выполнения сервисного вызова, который может загрузить некоторые данные и затем поместить их в localStorage. К сожалению, из-за некоторых асинхронных проблем мой localStorage пуст, когда я пытаюсь получить к нему доступ. JS не является моим основным языком, и у меня нет глубокого понимания того, как работают асинхронные вызовы, поэтому я хочу извлечь уроки из моего текущего примера.

JS код для выполнения запроса:

    function getRM() {
      var handleResponse = function (status, response) {
          localStorage.setItem('return_matrix', response);
      }
      var http=new XMLHttpRequest();
      var handleStateChange = function () {
           switch (http.readyState) {
              case 0 : case 1 : case 2 : case 3 : break;
              case 4 : // COMPLETED
                  handleResponse(http.status, http.responseText);
                  break;
              default: alert("error");
           }
      }
      http.onreadystatechange=handleStateChange;
      http.open("GET",'{% url 'returnMatrix'  %}', true);
      http.setRequestHeader('Content-type', 'application/json');
      http.setRequestHeader('X-CSRFToken', '{{  csrf_token }}');
      http.send(null);
    }

JS-код для обработки элемента локального хранилища, примененного к window.onload:

    function createTableData() {
      if (localStorage.getItem('return_matrix') === null) {
          getRM()
      }
      var returnMatrix = JSON.parse(localStorage.getItem('return_matrix'));
      //...
      /*save data to locat storage*/
      returnMatrix['years'] = years; // here I get an error that returnMatrix is null
      returnMatrix["present_value"] = sum;
      returnMatrix["actual_contributions"] = actualContributions;
      localStorage.setItem('return_matrix', JSON.stringify(returnMatrix))
      //...
    }

1 Ответ

0 голосов
/ 09 сентября 2018

Самый простой способ возобновить код после асинхронного вызова - воспользоваться функцией обратного вызова. Это будет выглядеть примерно так:

function getRM(callback) { // <--- accepts a callback param
  const handleResponse = function (status, response) {
    localStorage.setItem('return_matrix', response);
    callback(); // <--- calling the callback
  })

  const http=new XMLHttpRequest();
  // ...etc
}

И привык бы что-то вроде этого:

function createTableData() {
  if (localStorage.getItem('return_matrix') === null) {
    getRM(doWork);
  } else {
    doWork();
  }
}

// I split this out into a helper function because it sometimes needs to be
//   called synchronously, sometimes asynchronously, and i didn't want to
//   duplicate the code. 
function doWork() {
  const returnMatrix = JSON.parse(localStorage.getItem('return_matrix');
  //... etc
}

Обратные вызовы работают, но могут быть несколько сложными, если вы хотите объединить их в цепочку или устранить ошибки. Еще одна распространенная техника, которая улучшает это, - Обещания. Обещание - это объект, представляющий конечную ценность. Вы можете получить доступ к этому возможному значению, вызвав метод обещания .then и предоставив обратный вызов.

Многие библиотеки для выполнения http-запросов (например, axios , fetch ) возвращают обещание, поэтому вы можете работать с ними, не делая ничего лишнего. В вашем примере, хотя вы вручную делали XHR, и в него не встроены обещания. Но вы все равно можете добавить их, если хотите, что-то вроде этого:

function getRM() {
  // creating a promise object
  return new Promise((resolve, reject) => {
    const handleResponse = function (status, response) {
      localStorage.setItem('return_matrix', response);
      resolve(); //<--- calling resolve instead of callback
    }

    const http = new XMLHttpRequest();
    // ...etc
  });
}

И вы будете использовать это так:

function createTableData() {
  if (localStorage.getItem('return_matrix') === null) {
    getRM().then(doWork);
  } else {
    doWork();
  }
}

Теперь, когда код использует обещания, еще одно уточнение, которое мы можем сделать, - это использовать async / await, что немного упрощает синтаксис для работы с обещаниями. Эта версия будет выглядеть так:

async function createTableData() {
  if (localStorage.getItem('return_matrix') === null) {
    await getRM();
  }

  // I've moved the code back in line, since it's no longer needed in 2 places
  const http=new XMLHttpRequest();
  //... etc
}

И теперь он снова выглядит почти так же, как и раньше, за исключением того, что теперь getRM возвращает обещание, а createTableData будет ожидать разрешения этого обещания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...