javascript - javascript中的异步回调

标签 javascript

问题:无法将异步函数的返回值分配给 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);
}

正如您在上面的代码中看到的,mydataundefined。如何让 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 功能,例如 Promisesasync- 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/

相关文章:

javascript - 如何从 ws 客户端连接 socket.io?

javascript - 为什么将一个函数(属于一个对象)分配给一个变量会有这样的行为?

javascript - Node 服务器问题

javascript - 如何使用 JavaScript 从字符串中获取前 8 个字符和后 8 个字符?

javascript - DHTMLX addMarkedTimeSpan 每周都会阻止时间而不是特定日期

javascript - 在给定位置触发对元素的关注

javascript - 以 float 作为输入和输出的种子随机数,以实现可能的递归

javascript - 我如何定义一个简单的基本剑道网格并扩展它

javascript - 使用 laravel 在 jquery 中使用 window.location.href 时没有获得变量值

javascript - Material Design Lite 动态改变颜色