Node.js中循环执行Promise函数如何实现串行输出?
问题根源
forEach 不会等待传入的异步回调执行完毕——它会一口气遍历完整个数组,同时启动所有异步任务。每个回调里的 await 只在自身函数范围内生效,拦不住 forEach 继续跑下一个回调,所以所有 - person #i 会先被打印出来,等所有异步任务全部完成后,才会批量输出对应的person对象。
另外提一句:原始代码里的 fetchPerson 有个小bug——setTimeout(resolve(result), 3000) 会直接立刻执行 resolve(result),根本不会延迟3秒,正确写法是把resolve放进箭头函数里:setTimeout(() => resolve(result), 3000),你后来修改的代码已经修正了这个问题,但核心的顺序问题还是出在forEach上。
解决办法
换成 for...of 循环遍历数组,它能和 await 配合实现串行执行异步任务:
const PEOPLE_ADDRESSES = ['streetD', 'street2', 'streetA'] async function main() { for (const [i, address] of PEOPLE_ADDRESSES.entries()) { console.log(`- person #${i}`) const person = await fetchPerson(address) console.log(person) } } function fetchPerson(address) { const result = { address, age: Math.round(Math.random() * 100), } return new Promise((resolve) => setTimeout(() => resolve(result), 1500)) } main()
这样就能保证每完成一套流程(打印person序号 → 等待获取person数据 → 打印person对象),再执行下一个,完全符合你想要的输出顺序。
备选方案:用reduce串行串联Promise
如果喜欢函数式写法,也可以用reduce来累积Promise,实现串行执行:
async function main() { await PEOPLE_ADDRESSES.reduce(async (prevTask, address, i) => { // 等上一个异步任务做完再继续 await prevTask console.log(`- person #${i}`) const person = await fetchPerson(address) console.log(person) }, Promise.resolve()) }
这个方案通过reduce把每个异步任务串成链,每次都等前一个任务完成后再执行当前操作,同样能达到顺序输出的效果。
内容的提问来源于stack exchange,提问作者marielle
相关产品推荐
相关产品推荐

