问题:无法将异步函数的返回值分配给 mydata
全局变量。
我有一个函数正在调用另一个函数来获取和解析一些数据。但是,我无法访问函数外接收到的数据。
var mydata = loadJSON( (response) => {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
console.log(actual_JSON);
return actual_JSON;
});
console.log('mydata', mydata);
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', './my-data.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
正如您在上面的代码中看到的,mydata
是undefined
。如何让 actual_JSON
的数据可以在外部访问以供其他 javascript 函数使用?
最佳答案
为什么你会遇到这个问题?
要了解问题的根源,您需要了解 javascript 中调用堆栈和异步执行的概念。在这里我给你一个简短的介绍,但足以理解你的问题
javascript 中的异步执行发生在当前调用堆栈之外。您正在调用一个名为 loadJson 的函数,该函数接受一个回调,并且该回调在一个名为 onreadystatechange 的异步处理程序中执行。调用堆栈在不同执行阶段的状态如下图所示:
首先,调用栈是空的。
call stack
- - async handler
- - -------------
- - -empty-
- -
- - - - - -
然后调用 loadjson 并将其压入调用堆栈。
call stack
- - async handler
- - -------------
- - -empty-
- -
- loadJson-
- - - - - -
loadjosn 执行 XMLHttpRequest,这是一个异步代码。异步代码在调用堆栈之外执行,这里我们可以称之为 async-handler,它在那里等待直到异步执行完成。此时 loadjson 函数已完成并推出调用堆栈。因此此调用堆栈再次为空。
call stack
- - async handler
- - -------------
- empty - xhrHttpRequest ( wait until ajax finish fetching data )
- -
- - - - - -
当异步 xmlhttprequest 完成获取数据时。回调函数被插入调用堆栈。
call stack
- - async handler
- - -------------
- - empty ( async execution finished execution)
-callback -
- - - - - -
此时回调函数忘记了它是 laodJson 函数的回调,因为它不是从 loadjosn 函数内部调用的,而是从异步处理程序调用的。所以回调函数的执行就像一个单独的、独立的函数。从代码中可以看出回调是从 loadjson 调用的,但此时回调与 loadjson 函数没有关系。它是异步执行的结果。因此回调的调用不再与 loadjson 有任何关系。
这就是为什么您不能从 callback 或 loadjosn 返回任何将填充全局变量 mydata 的结果。
如何解决?
您可以遵循多种方式。您可以使用老派 continuation-passing-style
,或者您可以使用新的 es6 功能,例如 Promises
和 async
- await
.他们这样做的方式被称为延续传递风格。我假设你已经熟悉这种风格,所以这里我只提供 promise 和 async-await 风格以方便你。
promise 方式:
var mydata ;
loadJSON( (response) => {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
console.log(actual_JSON);
return actual_JSON;
}).then(response =>{ mydata = response;console.log(mydata)})
function loadJSON(callback) {
return new Promise(function (resolve,reject){
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', './my-data.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
resolve(callback(xobj.responseText));
}
};
xobj.send(null);
})
}
异步等待过程:
function loadJson(){
return new Promise(function(resolve,reject){
var xobj = new XMLHttpRequest()
xobj.onreadystatechange = function(){
if(xobj.readyState == 4 && xobj.status == 200){
resolve(xobj.response)
}
}
xobj.open('GET', './my-data.json', true);
xobj.send()
})
}
async function askForJson(){
var data = await loadJson()
return data
}
askForJson().then(data=>console.log(data))
关于javascript - javascript中的异步回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48594581/