javascript中的异步回调(asynchronous callback in javascript)

编程入门 行业动态 更新时间:2024-10-26 15:21:13
javascript中的异步回调(asynchronous callback in 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); }

正如您在上面的代码中看到的那样, mydata是undefined 。 如何让外部访问的actual_JSON数据供其他javascript函数使用?

Problem : can't assign returned value from asynchronous function to mydata global variable.

I have a function which is calling another function to get and parse some data. However, I am not acble to access the data received outside the function.

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

As you can see in the above code, mydata is undefined. How can I have the data of actual_JSON accessible outside for use by other javascript functions?

最满意答案

你为什么面临这个问题?

要理解问题的根源,您需要了解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 ) - - - - - - - -

当async xmlhttprequest完成获取数据时。 回调函数被推入callstack。

call stack - - async handler - - ------------- - - empty ( async execution finished execution) -callback - - - - - - -

到这时回调函数忘记了它是laodJson函数的回调,因为它不是从loadjosn函数内部调用而是从异步处理程序调用。 所以回调函数就像一个单独的独立函数一样执行。从代码中可以看出从loadjson调用回调,但此时回调与loadjson函数没有联系。 它是异步执行的结果。因此,回调调用与loadjson无关。

这就是为什么你不能从回调或loadjosn返回任何将填充全局变量mydata的结果。

你怎么解决它?

你可以遵循很多方法。 您可以使用旧式的continuation-passing-style ,或者您可以使用新的es6功能,如Promisesasync - await 。 他们这样做的方式被称为延续传递风格。 我假设你已经熟悉这种风格,所以在这里我只提供你的承诺和异步等待风格。

承诺方式:

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

Why you are facing this problem ?

To understand the root of the problem, you need to understand the concept of call-stack and async execution in javascript. Here i am giving you a brief introduction but enough to understand your problem

async execution in javascript happens outside of the current call stack. You are calling a function called loadJson which accepts a callback and the callback is executed inside an async handler called onreadystatechange. The status of the call stack in different stage of the execution has been illustrated below :

First, call stack is empty.

call stack - - async handler - - ------------- - - -empty- - - - - - - - -

Then loadjson is called and it's pushed into the call stack.

call stack - - async handler - - ------------- - - -empty- - - - loadJson- - - - - - -

loadjosn executes XMLHttpRequest which is an async code.Async code executes outside of the call stack, somewhere we may call it async-handler here, and it waits there until the async execution is finished. At this point the loadjson function is done with and pushed out of the call stack.So after this call stack is empty again.

call stack - - async handler - - ------------- - empty - xhrHttpRequest ( wait until ajax finish fetching data ) - - - - - - - -

When the async xmlhttprequest finished fetching data. the callback function is pushed into the callstack.

call stack - - async handler - - ------------- - - empty ( async execution finished execution) -callback - - - - - - -

By this time the callback function forgets that it was a callback for the laodJson function, because it's not called from inside loadjosn function rather it's called from a async handler. So the callback function executes like a separate , standalone function.It may appear from the code that the callback is called from loadjson , but at this point callback has no ties with loadjson function. it a result of an async execution.So invocation of callback has no ties with loadjson anymore.

that's why you can not return any result from callback or loadjosn that will populate the global variable mydata.

How you can solve it ?

you can follow many ways. You can use the old-school continuation-passing-style , or you can use new es6 features like Promises and async-await. They way you are doing it is called is continuation passing style. I assume you are already familiar with this style , so here i only providing the promise and async-await style for your convinience.

Promise way :

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

Async-Await procedure :

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

更多推荐

本文发布于:2023-07-20 12:46:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1199666.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:回调   javascript   callback   asynchronous

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!