Node.js多Promise链式调用forEach异步未等待致结果为空问题
问题原因
Array.prototype.forEach 不会等待内部传入的异步回调执行,回调里返回的Promise会被直接丢弃。你写的await arrayToDoc()只会等待forEach同步遍历完所有元素就立刻resolve,不会等待内部getOne的异步查询完成,因此后续逻辑会在所有查询返回前提前执行,才会出现打印顺序错乱、结果为空的问题。
另外原代码还有两个隐性bug:
newArray初始化为[{ MyTasks: [] }],是一个包裹了任务对象的数组,后续push时直接写newArray.MyTasks.push属于给数组对象本身加属性,不会写入你初始化的MyTasks数组getOne函数里的.then链式调用属于冗余写法,async/await本身已经可以直接拿到Promise结果,不需要额外套一层then
修复方案
根据你对执行顺序的需求选其中一种即可。
方案1:并发执行所有查询(性能优先)
用Promise.all配合map,同时发起所有查询,等所有查询全部完成后再走后续逻辑,执行效率最高:
app.post( "/api/tasks", async function (_req, res) { const newArray = [{ MyTasks: [] }]; const getOne = async (owner, taskID) => { return getOneDocument(owner, taskID); }; let toApproveTasks = await getToApproveTasks(_req.body.userID); console.log("1", toApproveTasks); // 等待所有异步查询执行完成 await Promise.all( toApproveTasks.TasksToApprove.map(async (element) => { const objToPush = await getOne(element.Owner, element.TaskID); console.log("1.5", objToPush); newArray[0].MyTasks.push(objToPush); }) ); console.log("2", newArray); const finalResult = await parseCosmosOutput(newArray); console.log("3", finalResult); res.status(200).send(finalResult); } );
方案2:顺序执行查询(顺序/并发限制优先)
如果需要严格按照数组元素的顺序逐个执行查询,或者需要控制并发数,可以用for...of循环,它会正确等待循环体内的await执行完成:
// 替换原arrayToDoc相关逻辑 for (const element of toApproveTasks.TasksToApprove) { const objToPush = await getOne(element.Owner, element.TaskID); console.log("1.5", objToPush); newArray[0].MyTasks.push(objToPush); }
注意:如果列表数据量很大,
Promise.all的全并发模式可能会瞬间打满数据库连接,这种场景建议按批次加并发控制,或者直接用顺序执行的for...of方案。
内容的提问来源于stack exchange,提问作者Krzysztof_K
相关产品推荐
相关产品推荐

