在Lodash each方法中使用Async Await结合Mongoose查询遇空数组问题
问题分析与解决方案
你的问题核心在于 Lodash的_.each是同步迭代工具,它无法处理异步函数返回的Promise,导致你的异步查询还没执行完,console.log(connectionIDs)就已经跑了,所以输出空数组。
为什么原来的写法不行?
_.each会遍历数组里的每个元素,调用你传入的async回调函数,但它完全不会理会这个回调返回的Promise——也就是说,它不会等待每个回调里的await UserProfile.findOne(...)执行完成,就直接继续往下走了。所以当你打印connectionIDs的时候,所有的异步查询都还在pending状态,数组自然是空的。
你提到尝试过await或者Promise.all但没解决,大概率是用法不对,下面给你两种正确的解决思路:
方案1:用for...of循环(串行执行)
for...of是原生支持异步等待的迭代器,它会在每次循环时等待await完成后再进入下一次迭代,能保证顺序执行:
let connectionIDs = []; // 注意要把这段代码放在async函数里 for (const connection of connections) { let id = connection.id; let connector = await UserProfile.findOne({phoneNumber: id}); connectionIDs.push({ name: connector.name.split(" ")[0], imageID: connector.imageID, phoneNumber: connector.phoneNumber }); } console.log(connectionIDs); // 现在能拿到正确结果了
方案2:用Promise.all结合Array.map(并行执行,效率更高)
如果你的查询之间没有依赖关系,推荐用这种方式——它会同时发起所有查询,等待全部完成后再处理结果,比串行更快:
// 把每个异步操作转换成Promise const promises = connections.map(async connection => { let id = connection.id; let connector = await UserProfile.findOne({phoneNumber: id}); return { name: connector.name.split(" ")[0], imageID: connector.imageID, phoneNumber: connector.phoneNumber }; }); // 等待所有Promise完成,结果会按原数组顺序返回 let connectionIDs = await Promise.all(promises); console.log(connectionIDs); // 正确结果
关键异步概念理清
async函数的返回值:任何async函数都会返回一个Promise,哪怕你没有显式写return。所以你传给_.each的回调其实是一个个独立的Promise,但_.each不会等待它们。await的作用范围:await只能在async函数内部生效,而且它只会阻塞当前的async函数上下文,不会影响外部的同步代码。- 同步迭代器vs异步迭代器:像
_.each、Array.forEach这类同步迭代器,都不支持处理异步回调的Promise,只有for...of或者专门的异步迭代工具才能正确等待异步操作完成。
内容的提问来源于stack exchange,提问作者Zafta
相关产品推荐
相关产品推荐

