Javascript 异步调用解决方法

Javascript 异步调用解决方法,javascript,asynchronous,Javascript,Asynchronous,我有一个JS脚本来执行服务调用,它可能会加载一些数据,然后将其放入本地存储。不幸的是,由于一些异步问题,当我尝试访问本地存储时,它是空的。 JS不是我的主要语言,我对异步调用的工作原理没有深入的了解,所以我想从我当前的示例中学习 执行请求的JS代码: function getRM() { var handleResponse = function (status, response) { localStorage.setItem('return_matri

我有一个JS脚本来执行服务调用,它可能会加载一些数据,然后将其放入本地存储。不幸的是,由于一些异步问题,当我尝试访问本地存储时,它是空的。 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);
    }
处理应用于window.onload的本地存储项的JS代码:

    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))
      //...
    }

异步之后恢复代码的最简单方法是使用回调函数。看起来是这样的:

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
}
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 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
}

回调可以工作,但当您想将回调链接在一起或处理错误时,回调可能会有点好斗。另一种改进这一点的常用技术是承诺。承诺是代表最终价值的对象。您可以通过调用promise的.then方法并提供回调来访问该最终值

许多用于执行http请求的库(例如)都会返回一个承诺,因此您可以在不做任何额外工作的情况下使用它们。在您的示例中,虽然您手动执行了XHR,但这并没有内置承诺。但是,如果需要,您仍然可以添加它们,如下所示:

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
}
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 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
}

既然代码使用了承诺,我们可以做的另一个改进就是使用async/await,这是一种更容易处理承诺的语法。该版本如下所示:

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
}
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 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将等待该承诺的解决。

async/await或promise可能是您需要的,为什么不使用
Promissions
async/await
谢谢大家,我对这一点很陌生,所以不知道。如果你想完全清楚,请阅读。非常感谢你的解释。我理解promises和async/await的语法。我也决定多读一些,但我认为你的回答完全解决了我的问题。非常感谢你。