Node.js中Axios请求未被消费函数await的问题排查
问题分析与解决
核心问题
你的消费函数mapResolvedBankCode提前返回的原因是:内部的异步请求没有被等待。forEach循环和for循环只会触发异步操作,不会等待它们完成,循环执行完毕后立刻调用了resolve,此时Axios请求还在后台运行,返回的数组并未被异步逻辑修改。
另外,accountResolved存在不必要的Promise嵌套(Promise构造器反模式),因为Axios本身就返回Promise,无需手动包裹一层new Promise。
步骤1:简化accountResolved函数
去掉冗余的Promise包裹,直接返回Axios的Promise链:
accountResolved: (atNumber, bkCode) => { return axios.get(`url/foo/bar`, { headers: { 'Authorization': 'token', } }) .then(response => response.status === 200) .catch(error => { console.log(error); return false; // 出错时返回false,与原逻辑一致 }); }
步骤2:修复mapResolvedBankCode的异步等待逻辑
需要收集所有异步操作的Promise,通过Promise.all等待全部完成后再返回结果。根据你的业务需求,有两种实现方式:
方式一:等待所有bankCode请求完成(保留原并发逻辑)
如果需要对每个账号尝试所有bankCode的请求,再返回结果:
mapResolvedBankCode: async (readCsvFileResponse, etransactBankCodes) => { const readCsvFileResponseClone = [...readCsvFileResponse]; // 收集所有账号的异步处理Promise const allAccountPromises = readCsvFileResponseClone.map(async (item) => { // 收集当前账号的所有bankCode请求Promise const bankCheckPromises = etransactBankCodes.map(bankCode => { return CsvService.accountResolved(item.accountNumber, bankCode) .then(result => { if (result) { console.log(`resolved account ${item.accountNumber}, with bank ${bankCode}`); item.bankCode = bankCode; } }) .catch(error => { console.error(`error in account no. ${item.accountNumber}::: `, error); item.bankCode = 'err'; }); }); // 等待当前账号的所有bankCode请求完成 await Promise.all(bankCheckPromises); }); // 等待所有账号的处理逻辑完成 await Promise.all(allAccountPromises); if (readCsvFileResponseClone.length > 0) { return readCsvFileResponseClone; } else { throw new Error('readCsvFileResponseClone not formed correctly'); } }
方式二:找到第一个匹配的bankCode就停止请求(优化性能)
如果只需找到第一个能匹配的bankCode,无需发起所有请求,可以改用for...of循环依次执行:
mapResolvedBankCode: async (readCsvFileResponse, etransactBankCodes) => { const readCsvFileResponseClone = [...readCsvFileResponse]; // 遍历每个账号,依次尝试bankCode for (const item of readCsvFileResponseClone) { try { for (const bankCode of etransactBankCodes) { const result = await CsvService.accountResolved(item.accountNumber, bankCode); if (result) { console.log(`resolved account ${item.accountNumber}, with bank ${bankCode}`); item.bankCode = bankCode; break; // 找到匹配项,停止当前账号的后续请求 } } } catch (error) { console.error(`error in account no. ${item.accountNumber}::: `, error); item.bankCode = 'err'; } } if (readCsvFileResponseClone.length > 0) { return readCsvFileResponseClone; } else { throw new Error('readCsvFileResponseClone not formed correctly'); } }
关键说明
forEach不支持异步等待,改用map配合Promise.all或for...of循环可以正确等待异步操作完成。- 使用
async/await语法比嵌套then/catch更易读,也更便于处理异步流程的等待逻辑。
内容的提问来源于stack exchange,提问作者Caesar
相关产品推荐
相关产品推荐

