Javascript 与普通for循环相比,数组的forEach是异步的
我刚开始探索es6中的Javascript 与普通for循环相比,数组的forEach是异步的,javascript,asynchronous,ecmascript-6,promise,Javascript,Asynchronous,Ecmascript 6,Promise,我刚开始探索es6中的async/await,我发现了一些令我惊讶的事情。基本上,forEach异步运行,而for循环同步运行就是一个例子 function getData(d) { return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(d.x+" %%%% ") },1000) }) } const data=[{x:"aaa"},{x:
async/await
,我发现了一些令我惊讶的事情。基本上,forEach
异步运行,而for
循环同步运行就是一个例子
function getData(d) {
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(d.x+" %%%% ")
},1000)
})
}
const data=[{x:"aaa"},{x:"bbb"}]
//async for loop
const makeRequest1 = async () => {
for (let i in data){
let value=data[i]
console.log(value)
value.p=await getData(value)
console.log(JSON.stringify(value)+ ' after')
}
// console.log(rr)
console.log(data)
console.log("Is it block ??")
return "done"
}
// { x: 'aaa' }
// {"x":"aaa","p":"aaa %%%% "} after
// { x: 'bbb' }
// {"x":"bbb","p":"bbb %%%% "} after
// [ { x: 'aaa', p: 'aaa %%%% ' }, { x: 'bbb', p: 'bbb %%%% ' } ]
// Is it block ??
// done
//async for loop
const makeRequest2 = async () => {
data.forEach(async (value)=>{
console.log(value)
value.p=await getData(value)
console.log(JSON.stringify(value)+ ' after')
})
console.log(data)
console.log("Is it block ??")
return "done"
}
// { x: 'aaa' }
// { x: 'bbb' }
// [ { x: 'aaa' }, { x: 'bbb' } ]
// Is it block ??
// done
// {"x":"aaa","p":"aaa %%%% "} after
// {"x":"bbb","p":"bbb %%%% "} after
makeRequest2().then((r)=>{
console.log(r)
})
我知道
for
和forEach
版本应该同步运行,为什么forEach
在这种情况下会变得异步 从承诺的角度考虑(这就是async/await真正的含义)
在第一种情况下,你就像你会做的那样,把承诺连在一起
getData(data[0])
.then((val) => console.log(...))
.then(() => getData(data[1])
.then(...
在第二种情况下,您只是一次调用所有承诺,因为forEach
会立即运行并注册所有承诺:
data.forEach(x => getData(x).then(val => console.log(...)));
注意,在这种情况下,getData(1)实际上并不等待getData(0)完成—没有链接。forEach中的等待只是在每个承诺中链接了一个then,并且只捕获forEach中的下一段代码
这意味着在第二种情况下,这些承诺将彼此异步运行
如果您确实希望这样做,但希望等待所有调用完成(使用第二种方法),则只需承诺即可。all+map方法:
const res = await Promise.all(data.map(item => getData(item)));
这将有效地在结果数组中的数组中的每个项上带来来自getData的所有结果,但请记住,这些调用都是异步的
此外,无法使用标准的forEach使函数互相等待。您可以使用reduce
操作来代替:
await data.reduce((intermPromise, item) => intermPromise.then(getData(item)), Promise.resolve());
这基本上是通过减少数组(从单元承诺开始)来链接对每个项的调用。最终外部等待将应用于与所有呼叫链接的最终承诺
还要注意使用map
方法与reduce
方法之间的区别,前者可以轻松地获得数组中的所有结果(但它是异步运行的),后者可以获得同步调用,但最终结果不会返回数组,实际上它只返回最后一次调用的结果
希望这有帮助。可能是因为回调前的
async
。@Weedoze非常可能,您是否有任何详细解释,您说您正在探索async
和wait
,然后去阅读文档。这将为您提供一个解释,您要传递给的异步函数。forEach
与外部异步函数不同步。for
案例只有一个异步函数,因此有明确的顺序。@loganfsmyth谢谢你指出了方向,我感觉我理解你在说什么,但不完全理解。我需要阅读更多的文档,希望能得到一些提示