javascript - 异步调用解决方法
问题描述
我有一个 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);
}
处理应用于 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
}
回调有效,但当您想将它们链接在一起或处理错误时可能会有些麻烦。另一种改进这一点的常用技术是 Promises。Promise 是一个代表最终值的对象。您可以通过调用 promise 的 .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();
}
}
现在代码使用了 Promise,我们可以做的进一步改进是使用 async/await,这是一种更容易使用 Promise 的语法。该版本如下所示:
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 将等待该承诺的解决。
推荐阅读
- c++ - 为什么会发生堆损坏?
- node.js - 我应该为 nginx/express 中的 https 做什么?
- xamarin - 构建时 Xamarin 实时播放器错误
- typeorm - TypeORM基本连接说明
- python - 使用 Minconda 创建新的 Python 安装
- c# - 无法在统一 2018 中触发事件
- flutter - 在 Row Flutter 中设置 Elements 之间的空间
- angular - 如何安全地将 Angular Material 添加到现有的 Angular 应用程序中?
- hibernate - 如何在 Spring Boot 中捕获 hibernate/jpa 约束违规?
- python - tensorflow:如何分配更新的numpy