如何等待批量请求及Promise全部完成后再执行回调函数?
问题分析与解决方案
首先,你的核心问题是外层的Promise.all没有等待内部每个item的三个请求完成——因为你在map的async函数里,没有返回内部Promise.all([promise, promise1, promise2])的结果,导致每个map迭代都默认返回了一个resolved为undefined的Promise,外层Promise.all自然会提前完成,拿到的是全是undefined的数组。
另外还有一个隐藏的竞态风险:你正在修改共享的connection对象的reporting_period属性,但map是并行执行的,多个item的请求会同时修改这个属性,可能导致请求参数混乱(比如第一个item的三个请求可能都用了最后一次设置的nextYear)。
下面是修复并优化后的代码:
async function requestJahrStatistic(jahreStatistic, callback){ // 封装请求逻辑,避免重复代码,同时避免共享connection的竞态问题 const sendPeriodRequest = async (item, period) => { // 复制connection对象,避免多个请求互相干扰 const conn = {...connection}; conn.statistic_id = item.statistic_id; conn.reporting_period = period; return new Promise((resolve, reject) => { sendHTTPRequest(item, (result) => { resolve(result); }, (error) => { // 别忘了处理错误,否则Promise会一直pending reject(error); }); }); }; // 外层Promise.all等待所有item的请求组完成 const allResults = await Promise.all( jahreStatistic.map(async (item) => { const periods = getReportingPeriod(item.period); // 发起当前item的三个请求,等待全部完成后返回结果数组 return Promise.all([ sendPeriodRequest(item, periods.prevYear), sendPeriodRequest(item, periods.actualYear), sendPeriodRequest(item, periods.nextYear) ]); }) ); // 所有请求完成后调用回调 callback(allResults); }
关键改动说明:
- 返回内部Promise.all的结果:在
map的async函数里,直接return Promise.all([...]),这样外层Promise.all才能收集到每个item的三个请求结果数组。 - 封装请求函数并隔离connection:创建
sendPeriodRequest函数,每次请求都复制一个独立的connection对象,避免并行修改导致的参数混乱。 - 添加错误处理:给
sendHTTPRequest加上错误回调,调用reject,避免某个请求失败时Promise一直pending。 - 简化async/await用法:用
await替代嵌套的.then,让代码逻辑更线性易读。
如果你的sendHTTPRequest本身可以改造成返回Promise的形式,代码还能更简洁:
// 先把sendHTTPRequest包装成Promise版本 const sendHTTPRequestPromise = (item, conn) => { return new Promise((resolve, reject) => { sendHTTPRequest(item, resolve, reject); }); }; // 然后在requestJahrStatistic里直接用 async function requestJahrStatistic(jahreStatistic, callback){ const allResults = await Promise.all( jahreStatistic.map(async (item) => { const periods = getReportingPeriod(item.period); const createConn = (period) => ({...connection, statistic_id: item.statistic_id, reporting_period: period}); return Promise.all([ sendHTTPRequestPromise(item, createConn(periods.prevYear)), sendHTTPRequestPromise(item, createConn(periods.actualYear)), sendHTTPRequestPromise(item, createConn(periods.nextYear)) ]); }) ); callback(allResults); }
这样整个逻辑更清晰,也彻底解决了并行请求的参数干扰问题,同时确保外层等待所有请求完成后再执行回调。
内容的提问来源于stack exchange,提问作者EAzevedo
相关产品推荐
相关产品推荐

