Promise.all未按预期工作,回调提前返回致Batch List为空
咱们来拆解下你代码里导致问题的几个关键错误,然后给出修正方案:
问题根源
你的代码里有三个核心问题,导致Promise.all还没等所有异步操作完成就触发了callback,最终batchList是空的:
promises数组根本没被填充
你用了promises.concat(promise),但concat是返回新数组,不会修改原promises数组,所以这个数组一直是空的。Promise.all([])会立即resolve,这时候所有getBatchList的回调还没执行,batchList自然没内容。回调风格函数和async/await不匹配
this.getBatchList是基于回调的方法,你用await去等它,但它并没有返回Promise,所以await完全不起作用。而且batchList的修改是在回调里,这个回调的执行时机完全不受你的异步流程控制。多余的嵌套async函数
runAsyncFunctions的嵌套完全没必要,反而把异步流程搞复杂了,增加了出错的概率。
修正方案
首先,我们需要把回调风格的getBatchList封装成Promise版本(如果没法修改原方法的话),这样才能用async/await正确管理异步流程:
// 把回调式的getBatchList转成Promise版本 const getBatchListPromise = (requestId, mode) => { return new Promise((resolve, reject) => { this.getBatchList(requestId, mode, null, null, (err, result) => { if (err) reject(err); else resolve(result.items); }); }); };
然后修改主函数的逻辑,正确收集并等待所有异步操作:
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback) { let results = {}; let requestList = []; let response = {}; new Promise((resolve, reject) => { this.getRequestList(object, limit, lastEvaluatedKey, (err, result) => { console.log(result); results = result; if (err) reject(err); else resolve(); }); }) .then(async () => { requestList = requestList.concat(results.items); // 正确收集所有异步操作的Promise const promises = requestList.map(request => { return getBatchListPromise(request.requestID.S, mode); }); // 等待所有Promise完成,拿到所有批次数据 const allBatchItems = await Promise.all(promises); // 把二维数组合并成一维,得到完整的batchList const batchList = allBatchItems.flat(); // 构造响应再调用callback response = { "requests": requestList, "batches": batchList, "lastEvaluatedKey": results.LastEvaluatedKey }; callback("", response); }) .catch((error) => { console.log(error); callback(error, response); }); }
额外优化:全async/await改写
如果把getRequestList也封装成Promise,咱们可以把整个函数改成全async/await的写法,逻辑更清晰:
// 封装getRequestList为Promise版本 const getRequestListPromise = (object, limit, lastEvaluatedKey) => { return new Promise((resolve, reject) => { this.getRequestList(object, limit, lastEvaluatedKey, (err, result) => { if (err) reject(err); else resolve(result); }); }); }; // 全async/await版本的主函数 async getByReferenceID(object, mode, limit, lastEvaluatedKey, callback) { let response = {}; try { // 先获取请求列表 const results = await getRequestListPromise(object, limit, lastEvaluatedKey); const requestList = results.items; // 收集所有批次请求的Promise const promises = requestList.map(request => { return getBatchListPromise(request.requestID.S, mode); }); // 等待所有批次请求完成 const allBatchItems = await Promise.all(promises); const batchList = allBatchItems.flat(); // 构造响应并返回 response = { "requests": requestList, "batches": batchList, "lastEvaluatedKey": results.LastEvaluatedKey }; callback("", response); } catch (error) { console.log(error); callback(error, response); } }
这样修改后,Promise.all会真正等待所有getBatchList操作完成,batchList就能正确填充数据,callback也会在所有异步操作完成后才被调用。
内容的提问来源于stack exchange,提问作者khushboo mishra

