Array.reduce中使用异步逻辑执行时脚本报错的问题求解
问题根本原因
Array.reduce的回调如果是async函数,那么每次迭代返回的都是Promise对象,而非你预期的累计结果对象。下一轮迭代拿到的result参数是上一轮返回的未resolve的Promise,直接调用.push方法自然会抛出属性不存在的错误。
修复方案1:修改reduce回调,先等待上一轮累计结果resolve
如果你需要按数组顺序串行执行查询操作,可以直接在现有代码基础上调整,每次迭代先等待上一轮的累计结果resolve后再操作:
const { readyScoreRequests, remainingScores, } = await scoreRequests.reduce(async (resultPromise, score) => { // 先等待上一轮的累计结果resolve const result = await resultPromise; const { profile } = score; const importedScore = score.scoreId ? await importedScoreService.findOne({ where: { id: score.scoreId }, }) : null; const scoreDate = importedScore ? moment(importedScore.createdOn).format('MM/DD/YYYY') : 'New Score'; const scoreInfo = { status: score.status.charAt(0).toUpperCase() + score.status.slice(1), scoreDate, name: profile ? profile.name : null, email: score.companyEmail ? score.companyEmail : null, city: profile ? profile.city : null, state: profile ? profile.state : null, logo: profile ? profile.logo : null, }; if (score.status === 'ready') { result.readyScoreRequests.push(scoreInfo); } else { result.remainingScores.push(scoreInfo); } return result; }, { readyScoreRequests: [], remainingScores: [] });
修复方案2:并行处理异步查询后再拆分(性能更优)
如果查询操作没有先后顺序依赖,建议先批量并行跑完所有异步查询,再一次性拆分数组,执行效率远高于串行的reduce方案:
// 并行获取所有score的处理结果 const scoreInfoList = await Promise.all(scoreRequests.map(async (score) => { const { profile } = score; const importedScore = score.scoreId ? await importedScoreService.findOne({ where: { id: score.scoreId }, }) : null; const scoreDate = importedScore ? moment(importedScore.createdOn).format('MM/DD/YYYY') : 'New Score'; return { scoreInfo: { status: score.status.charAt(0).toUpperCase() + score.status.slice(1), scoreDate, name: profile ? profile.name : null, email: score.companyEmail ? score.companyEmail : null, city: profile ? profile.city : null, state: profile ? profile.state : null, logo: profile ? profile.logo : null, }, isReady: score.status === 'ready' }; })); // 拆分两个数组 const readyScoreRequests = []; const remainingScores = []; scoreInfoList.forEach(item => { if (item.isReady) { readyScoreRequests.push(item.scoreInfo); } else { remainingScores.push(item.scoreInfo); } });
内容的提问来源于stack exchange,提问作者Chicha
相关产品推荐
相关产品推荐

