JavaScript循环中如何等待多个Promise全部resolve后再执行后续逻辑
核心问题梳理
Array.forEach没有返回值,方法直接返回forEach的执行结果相当于返回undefined,不符合返回Promise的类型要求,触发“并非所有代码路径都有返回值”的报错- 混用Promise和Observable,异步流程没有统一管理,手动计数判断全部上传完成的方式容错性极低
- 嵌套层级过深,逻辑出现断层,内层的return无法透传到方法外层的调用方
修正后代码
import { firstValueFrom } from 'rxjs'; // rxjs 7+ 版本需要引入 // 可根据finilize的返回值调整Promise泛型,此处默认update返回Promise<void> createSubmission(sub: Submission, files: Files[]): Promise<void> { // 把每个文件的上传、获取下载链接逻辑包装为独立Promise const uploadTasks = files.map(async file => { const storageRef = this.storage.ref(`files/${file.name}`); // 等待文件上传完成 await storageRef.put(file); // Observable转Promise,rxjs 6及以下用.toPromise(),7+用firstValueFrom return firstValueFrom(storageRef.getDownloadURL()); }); // 等待所有文件任务全部执行完成,自动返回全量下载链接数组 return Promise.all(uploadTasks).then(urlArray => { sub.filesUrls = urlArray; // 透传finilize的Promise,调用方可直接感知到最终提交完成状态 return this.finilize(sub); }); } finilize(sub: Submission): Promise<void> { const subRef = this.db.database.ref(`/submissions/${sub.medicUid}`).push(); const subKey = subRef.getKey(); sub.uid = subKey; return subRef.update(sub); }
关键修改说明
- 用
Array.map替代Array.forEach,收集所有文件的异步任务为Promise数组,保证方法的返回值始终是Promise类型 - 用
Promise.all统一管理所有异步任务,无需手动计数判断是否全部完成,天然支持任务失败时直接抛出异常,避免无意义的等待 - 统一异步范式,将Observable类型的
getDownloadURL()转为Promise,避免两种异步模式混用导致的流程失控 - 直接透传最终的提交Promise,调用方可以直接通过
await createSubmission()的方式等待整个流程执行完成
可选适配方案
如果需要容忍部分文件上传失败、仅提交上传成功的文件链接,可以把Promise.all替换为Promise.allSettled,自行过滤成功的返回结果即可。
内容的提问来源于stack exchange,提问作者Ghadir
相关产品推荐
相关产品推荐

