为何reduce会顺序等待Promise,而forEach不会?
为何reduce会顺序等待Promise,而forEach不会?
先看reduce的执行逻辑
对应的代码:
const promises = [ new Promise(r => setTimeout(r, 10000, "Hi")), new Promise(r => setTimeout(r, 500, "second")), new Promise(r => setTimeout(r, 100, "third")) ]; promises.reduce(async(a, promise) => { await a; const p = await promise; console.log(p); }, Promise.resolve());
这段代码的核心是reduce的累加器机制和异步回调的链式依赖:
- 第一次迭代:累加器初始值是
Promise.resolve(),await a会立即完成,随后开始等待第一个Promise(10秒后resolve)。同时这个async回调会返回一个处于pending状态的Promise,作为下一次迭代的累加器a。 - 第二次迭代:必须先
await a——也就是等待第一次回调返回的Promise完成(也就是第一个Promise的结果打印完毕后),才会去等待第二个Promise并执行打印。 - 第三次迭代同理,要等第二次的异步流程完全结束,才会启动第三个Promise的结果获取和打印。
哪怕三个Promise在创建时就已经同时开始计时,await a强制了迭代之间的顺序依赖,最终输出顺序是Hi、second、third。
再看forEach的执行逻辑
对应的代码:
const promises = [ new Promise(r => setTimeout(r, 10000, "Hi")), new Promise(r => setTimeout(r, 500, "second")), new Promise(r => setTimeout(r, 100, "third")) ]; promises.forEach(async promise => { // try to force the delay of the "promise" in the promises array. await 3; const p = await promise; console.log(p); });
forEach的特点是同步遍历所有元素,触发独立的异步任务:
- 三个async回调会在遍历过程中被立刻连续调用,每个回调内部的
await 3只是短暂进入微任务队列(等价于await Promise.resolve(3)),很快就会完成。 - 之后三个
await promise是并行等待状态,哪个Promise的计时先结束(先resolve),对应的console.log就会先执行。 - 因为第三个Promise仅需100ms,第二个500ms,第一个10秒,所以输出顺序是
third、second、Hi(你描述的second、third、first应为笔误)。
本质区别
reduce通过累加器将每一次的异步操作串联成一条链式流程,后一次迭代必须等待前一次的异步逻辑完全完成。forEach只是同步触发了多个互相独立的异步函数,这些函数之间没有任何等待依赖,属于并发执行,结果输出顺序完全由各自Promise的resolve时间决定。
内容的提问来源于stack exchange,提问作者Toban Harnish
相关产品推荐
相关产品推荐

