如何在等待Promise resolve时执行计算并保证异步调用顺序
实现思路
核心逻辑是计算操作和send的等待过程并行,发送动作严格串行:
原代码的问题是await send()会阻塞整个循环,必须等上一个发送完全结束才会进入下一轮计算下一个值,计算和发送完全串行,平白浪费了send等待的时间。优化后不需要等上一个send()完全结束就可以启动下一个值的计算,但必须等上一个send() resolve之后才会触发下一个send()调用,从根源上保证发送顺序和原数组完全一致。
具体实现步骤:
- 提前预计算第一个待发送的值,避免第一轮空等
- 遍历数组时,每轮先触发当前值的send拿到Promise,不等待它完成,立刻并行启动下一个值的计算
- 等当前send的Promise状态变为已完成后,把提前算好的下一个值作为下一轮的待发送值,重复流程
- 循环结束后单独等待最后一个值发送完成即可
可直接运行的实现代码
const arrayToSend = [1,2,3,4,5,6,7,8,9] function send(x){ // 发送值,1秒后返回成功 return new Promise(resolve=>{ setTimeout(()=>{ resolve() console.log('sent '+x) },1000) }) } function calculate(x){return x**2} // 耗时计算逻辑 async function loopAndSendArray(){ if (arrayToSend.length === 0) return // 提前计算第一个待发送的值 let nextCalculatedVal = calculate(arrayToSend[0]) // 从第二个元素开始遍历,每轮等待当前发送的同时计算下一个 for (let i = 1; i < arrayToSend.length; i++) { const currentSendPromise = send(nextCalculatedVal) // 等待当前发送的同时,并行计算下一个值,不浪费等待时间 nextCalculatedVal = calculate(arrayToSend[i]) await currentSendPromise } // 等待最后一个值发送完成 await send(nextCalculatedVal) } // 测试调用 loopAndSendArray()
效果说明
- 发送顺序严格和原数组一致:控制台输出顺序永远是
sent 1、sent 4、sent 9...sent 81,不会出现乱序 - 耗时比原方案更短:原方案每轮需要消耗「计算耗时 + 1秒发送等待」,总耗时为
9*(计算耗时+1s);优化后计算过程和1秒发送等待完全重叠,总耗时约为计算耗时 + 9*1s,计算逻辑越重,耗时优化效果越明显。
内容的提问来源于stack exchange,提问作者Daavee18
相关产品推荐
相关产品推荐

