如何从Array.reduce返回Promise?异步处理遇数据缺失问题
问题描述
我正在使用Array.reduce遍历对象数组,并尝试从中返回Promise。在reduce方法内完成修改后,Promise解析出的对象中reviewCards['departments']有正常数据,但reviewCards['genders']为空,我认为并非所有Promise都已正确解析。
请问如何将最终对象以Promise形式返回?
public getCompanyReviewCards( reviewGroups: ICompanyReviewGroups, reviews: CompanyReview[], ): Promise<{[key: string]: ICompanyReviewCard}> { return new Promise((resolve, reject) => { const reviewCards = Object.keys(reviewGroups).reduce( async (reviewCards: ICompanyReviewCards, groupKey: string) => { const group = reviewGroups[groupKey]; reviewCards['genders'] = reviewCards['genders'] || []; reviewCards['departments'] = reviewCards['departments'] || []; //Department wise cards //This block is executing properly if (groupKey === '_departmentGroup') { const departmentsCards = await this.getCardsByDepartments(group); reviewCards['departments'] = departmentsCards; } //Gender wise cards //This block is not executing properly if (groupKey === '_genderGroup') { const gendersCards = await this.getCardsByGender(group); reviewCards['genders'] = gendersCards; } return reviewCards; },Object.create(null), ); resolve(reviewCards); }) }
问题原因
核心问题是你把async函数作为reduce的回调,导致累加器每次都是Promise,而非直接的对象。第一次迭代时,回调返回的是Promise,但第二次迭代时,reviewCards参数是上一次的Promise,你直接对它操作(比如reviewCards['genders'] = ...)其实是在Promise对象上添加属性,而不是等待Promise解析后的实际对象。这就导致后续的异步操作没有正确作用到目标对象上,最终genders数据丢失。
修正方案
需要在reduce的回调里先等待上一次的Promise解析,拿到实际的reviewCards对象后再进行操作。同时,不需要额外包裹一层new Promise,因为reduce最终会返回一个Promise,直接返回它即可:
public getCompanyReviewCards( reviewGroups: ICompanyReviewGroups, reviews: CompanyReview[], ): Promise<{[key: string]: ICompanyReviewCard}> { // 直接返回reduce生成的Promise return Object.keys(reviewGroups).reduce( async (accPromise, groupKey: string) => { // 先等待上一次的Promise完成,拿到实际的reviewCards对象 const reviewCards = await accPromise; const group = reviewGroups[groupKey]; // 初始化默认值 if (!reviewCards.genders) reviewCards.genders = []; if (!reviewCards.departments) reviewCards.departments = []; if (groupKey === '_departmentGroup') { const departmentsCards = await this.getCardsByDepartments(group); reviewCards.departments = departmentsCards; } if (groupKey === '_genderGroup') { const gendersCards = await this.getCardsByGender(group); reviewCards.genders = gendersCards; } return reviewCards; }, // 初始值是一个resolved的Promise,包含空对象 Promise.resolve(Object.create(null) as ICompanyReviewCards) ); }
关键修改点
- 初始值改为Promise.resolve的空对象:确保第一次迭代时
accPromise是一个已解析的Promise,能拿到实际对象。 - 每次迭代先等待accPromise解析:
const reviewCards = await accPromise,确保操作的是实际的对象而非Promise。 - 去掉外层多余的new Promise:reduce最终返回的就是Promise,直接return即可,避免嵌套Promise。
这样修改后,所有异步操作都会按顺序执行,genders和departments的数据都会正确填充到最终对象中。
内容的提问来源于stack exchange,提问作者RAHUL KUNDU
相关产品推荐
相关产品推荐

