JavaScript遍历Promise数组时如何按原数组顺序输出结果
问题原因
你当前代码输出乱序的核心原因是:
- 你在构建
promises数组时,所有wait()调用就已经立刻启动了内部的定时器,每个Promise的状态变更时机完全由自身传入的延迟时间决定 - 直接循环给每个Promise单独绑定
then回调时,哪个Promise先变为已兑现状态,对应的回调就会先触发执行,因此最终会按照延迟从短到长输出1、2、3、4、5,和数组原有顺序无关
实现方案
你不需要修改Promise的并行执行逻辑(如果改成串行执行总耗时会变成15秒,远高于并行的5秒),只需要保证输出动作严格按数组顺序触发即可,最简洁的实现方式是用async/await按顺序等待每个Promise的结果,所有Promise依然会保持并行执行:
function wait(seconds) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(seconds); }, seconds * 1000); }); } const promises = [ wait(1), wait(3), wait(2), wait(4), wait(5), ]; (async () => { for (var promise of promises) { const seconds = await promise; console.log(`Waited ${seconds} seconds`); } })();
执行逻辑说明
- 所有Promise在数组创建时就已经并行启动计时,总耗时依然是最长的5秒,不会变成串行累加的15秒
await会按数组顺序依次取每个Promise的兑现结果:如果当前位置的Promise还没兑现,就等待它兑现后输出;如果当前位置的Promise早就兑现了(比如例子中2秒就兑现的第三个Promise),会在前面的Promise结果输出后立刻打印对应内容- 最终输出顺序完全和数组顺序一致:
Waited 1 seconds Waited 3 seconds Waited 2 seconds Waited 4 seconds Waited 5 seconds
如果你不想用async函数,也可以用缓存结果+指针的方式实现同等效果:
let currentPrintIndex = 0; const cachedResults = new Array(promises.length); for (let i = 0; i < promises.length; i++) { const promise = promises[i]; promise.then(seconds => { cachedResults[i] = seconds; // 按顺序输出已经拿到结果的项 while (currentPrintIndex < promises.length && cachedResults[currentPrintIndex] !== undefined) { console.log(`Waited ${cachedResults[currentPrintIndex]} seconds`); currentPrintIndex++; } }); }
注意不要把Promise改成串行执行(比如在循环里才调用
wait()创建Promise再await),否则会大幅增加总执行时间。
内容的提问来源于stack exchange,提问作者c136
相关产品推荐
相关产品推荐

