嵌套异步函数返回Pending Promise问题:原因及解决方案
问题:异步函数返回Pending状态的Promise,如何解决?
我编写了getSettlementByUser异步函数,通过多层嵌套的async/await与Promise.all处理数据库查询逻辑,但最终输出的promiseValue仍包含处于Pending状态的Promise。明明已经用了Promise.all处理嵌套异步,却还是出现这个问题,请问原因是什么,该怎么解决?
代码示例
async getSettlementByUser(email): Promise<any> { let listofTerminalId = []; // Get current user let user = await this.userModel.findOne({ email: email }); // get list of sn let tpeIndexes = user.bindedSn.map((item) => item); //list des tpes binded to current user let tpe = tpeIndexes.map(async (index) => { let list = await this.tpeModel.find({ sn: index }); // console.log('liste des tpes', list); let terminalId = list.map((item) => item.terminalId); // console.log('terminalId', ...terminalId); listofTerminalId.push(...terminalId); console.log('listofTerminalId', listofTerminalId); return await listofTerminalId.map(async (item) => { return await this.modelSettlement .find({ terminalID: item }) .then((res) => res) .catch((err) => console.log(err)); }); // console.log('settlement', settlement); // return settlement; }); let promiseValue = await Promise.all(tpe); console.log('promiseValue', promiseValue); // // return promiseValue; // return tpe; }
输出结果
promiseValue [ [ Promise { <pending> } ], [ Promise { <pending> }, Promise { <pending> } ], [ Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ] ]
问题原因
- 内层Promise未被等待:你在
listofTerminalId.map(async (item) => { ... })里返回的是一个Promise数组,但没有对这个数组使用Promise.all。外层的Promise.all(tpe)只等待了tpe数组里的外层异步函数完成,但每个外层函数返回的是未被处理的内层Promise数组,所以这些内层Promise依然处于Pending状态。 - 全局变量导致逻辑混乱:你在循环中修改全局的
listofTerminalId,多个异步操作同时向这个数组push数据,会导致每次循环都基于整个数组去查询结算数据,重复查询之前的terminalId,同时异步操作的顺序不可控,进一步加剧了Promise未完成的问题。
解决方法
重构后的代码
async getSettlementByUser(email): Promise<any> { // 获取当前用户 const user = await this.userModel.findOne({ email: email }); // 直接使用绑定的sn列表,无需额外map const tpeIndexes = user.bindedSn; // 并行处理每个sn对应的结算数据 const settlementResults = await Promise.all(tpeIndexes.map(async (sn) => { // 获取当前sn关联的所有tpe记录 const tpeList = await this.tpeModel.find({ sn }); // 提取当前sn对应的terminalId列表 const terminalIds = tpeList.map(item => item.terminalId); // 等待当前sn下所有terminalId的结算查询完成 return Promise.all(terminalIds.map(async (terminalId) => { try { return await this.modelSettlement.find({ terminalID: terminalId }); } catch (err) { console.error('查询结算数据失败:', err); return null; // 根据业务需求返回错误默认值 } })); })); console.log('最终结算结果:', settlementResults); return settlementResults; }
关键修改点
- 移除全局共享变量:每个sn对应的terminalId单独处理,避免重复查询和异步操作间的数据干扰。
- 内层Promise也用Promise.all等待:在
terminalIds.map外层包裹Promise.all,确保当前sn下的所有结算查询都完成后才返回结果。 - 简化异步逻辑:去掉不必要的
then/catch,改用try/catch和await配合,代码风格更统一,错误处理更清晰。 - 避免冗余操作:
user.bindedSn.map((item) => item)是冗余操作,直接使用user.bindedSn即可。
内容的提问来源于stack exchange,提问作者Fredrick
相关产品推荐
相关产品推荐

