当我做这样的事情时,我意识到:
for (const entity of someArr) {
console.log('start now!')
await doSomeAsycAction()
console.log('waited X secs!')
}
它打印出来:
start now!
waited X secs!
start now!
waited X secs!
...
但是当我使用地图时:
arr.map(async entity => {
console.log('start now!')
await doSomeAsycAction()
console.log('waited X secs!')
})
它打印出来:
start now!
start now!
start now!
...
waited X secs!
waited X secs!
waited X secs!
...
有人可以解释为什么会这样吗?
答案 0 :(得分:1)
这两个流程之间的区别在于,第一个流程(使用for
,for..in
或for..of
)按顺序运行循环迭代,而另一个流程(使用{{1} },map
,filter
,reduce
等正在(如果在映射函数中的某处使用forEach
符号的情况下)正在运行。
在async
循环中,下一个迭代必须等待上一个迭代完成。这使您可以进行一些与下一次迭代相关的异步操作。
相反,使用async方法独立运行每个迭代,因此您不能依赖当前迭代中的其他迭代。这类函数将函数作为参数接收,并立即对数组中的每个项目执行该函数。
将每次迭代都视为独立的Promise执行。运行异步函数时,for
符号表明此操作可能需要一段时间(即I / O,DB调用,网络操作...),并且让当前执行函数之外的代码继续进行(并且在异步调用返回后,稍后再恢复)。 await
函数会看到当前迭代很忙,然后继续下一个迭代。将来会恢复并执行map
。
您可以使用console.log('waited X secs!')
循环以这种方式模拟异步执行的相同行为(可能有助于证明两者之间的区别):
for
async-await语法在每个函数范围内都有效,for (const entity of someArr) {
(async () => {
console.log('start now!')
await doSomeAsycAction()
console.log('waited X secs!')
})()
}
定义了一个新的函数范围(该函数作为参数传递给该函数),就像在每次迭代中执行的(匿名)函数一样我的例子。希望对理解有所帮助。
要注意的重要一件事是map
的每次迭代都不会返回您期望的映射值,而是一个可以用该值解决的承诺。因此,如果尝试依赖映射的数组值之一-必须在其前面添加一个map
,否则该值类型仍然是一个保证。看下面的例子:
await
答案 1 :(得分:-2)
基本数组原型循环函数(例如forEach,map,filter,find等)不等待下一次迭代。它们的基本行为是迭代不等待。如果要使用类似等待功能,请尝试使用以下类似方式
for (const event of events) {
if (failure or conditional) {
continue;
}
}