.map 中的 async await 在幕后如何工作?

问题描述

这是我写的代码

let aop = [
    'https://api.coindesk.com/v1/bpi/currentprice.json','https://datausa.io/api/data?drilldowns=Nation&measures=Population','https://api.publicapis.org/entries'
]; 
        
(async function (){
    Promise.all(aop.map(async url => {
        let response = await fetch(url);
        let json =  await response.json();
        return json;
    })).then(x => console.log(x))
} ());

(function functionThatTakes30SecondsToFinish (){
    // Some heavy lifting tasks
}())

我得到了我想要的东西,但我想知道它是如何工作的。

Promise.all 需要一组 promise,所以我使用 .map 来做到这一点。

现在让我困惑的事情是在第一次迭代中,对于第一个 url,fetch 将返回一个新的 Promise,然后遇到 await 关键字。由于函数调用的优先级高于 await 关键字,因此首先返回一个 promise。

我知道 await 会将您抛到当前执行上下文之外的一层,然后在 promise 得到解决后,收集其余代码并将其放入微任务队列以供执行。

但如果是这种情况,我们的第一个 promise 将被返回,并且我们将被抛到全局执行上下文之外的一层执行下一个函数functionThatTakes30SecondsToFinish()

显然没有任何函数需要那么长时间才能完成,但只是为了举例,让我们假设一下。

一旦这个耗时的函数完成,我们是不是只处理了一个 URL?那也只能退了?

无论如何,假设 5 秒后我们收到了第一个响应,然后 await获取其下方的代码

let json =  await response.json();
return json;

...并将其放入微任务队列以供稍后执行

如果这仅适用于一个 URL,那么我们如何再次返回 map

或者,这是我可以假设正在发生的第二件事:

map 将遍历每个 url,返回 promise,然后将所有这些代码都带入其内部隐藏数组,而不是将任何内容返回到最终返回的内部隐藏数组中:

let json =  await response.json();
return json;

...并将其放入微任务队列以供稍后执行

所以这就像 map 暂停每个元素的回调函数

我很困惑,我什至不能正确地问这个。有人可以帮我解决这个问题吗?

解决方法

事实更接近你的第二个描述。

当一个 async 函数被执行时,它会在遇到 await返回(在评估它后面的表达式之后)。 .map 的行为是在第一个回调调用返回后,它将执行下一个元素的回调,等等。当它们遇到 await 时,它们中的每一个都会返回。所有这些都是同步发生的。

所以当 .map 完成所有回调后,它返回一个包含结果的数组。在这种情况下,结果都是承诺。

Promise.all 然后被执行,它创建了另一个承诺。 then 方法已在其上执行,但尚未执行其回调。

然后执行“繁重”代码。

一旦完成,并且调用堆栈为空,promise 作业队列将被监控。对于得到响应的 fetch 调用,该队列中将有一个作业。它甚至可能是 3 个作业,如果在那个繁忙的时期,所有三个请求的 HTTP 响应都到达了。

这些作业对应于带有 await 的已解决承诺。具有 await 的函数的执行上下文将被恢复,并继续执行,等等。如果没有更多要执行的内容,则将处理该队列中的下一个作业,从而导致类似的情况,等等。

由于有更多的 awaits(伴随着 .json() 调用),该函数将再次返回,这一次使调用堆栈为空,这将再次导致一个 promise 作业被添加到队列(当 .json() 完成其工作时)。

当所有这些带有 await 的 promise 都解决了,并且执行之后的所有代码时,传递给 Promise.all 的 promise 都会解决。这将依次解析 Promise.all 创建的承诺,因此链接的 then 回调将执行。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...