使用async/await搭配reduce批量上传图片时字段缺失问题
问题原因
- 异步
reduce的累加器传递逻辑不符合预期:async函数的返回值永远是Promise类型,因此每一轮迭代拿到的累加器acc实际上是上一轮返回的Promise对象。当前代码传入的初始值为普通空对象{},类型与后续迭代的Promise类型累加器不一致,部分运行环境下会出现第二轮迭代的赋值未同步到最终结果的问题。 - 另一种高频触发场景是代码中
reduce的第二个参数(初始值)传递存在语法疏漏,导致reduce未识别到传入的{}作为初始值,默认将数组第一个元素"logoUrl"作为初始累加器,仅执行一次迭代,最终仅生成第一个字段。
解决方法
提供三种可落地的实现方案,可根据实际需求选择:
方案1:修正异步reduce的初始值
将初始值替换为Promise.resolve({}),保证每一轮迭代拿到的累加器类型统一,避免状态丢失:
const imageField = ["logoUrl", "fullLogoUrl"] const onCreate = async (submitData: any) => { const uploadImageField = await imageField.reduce( async function (acc: any, cur: string) { const resolvedAcc = await acc; const url = await uploadImage(submitData.general[cur][0]); resolvedAcc[cur] = url; return resolvedAcc; }, Promise.resolve({}) // 初始值替换为已resolve的空对象Promise ); console.log(uploadImageField); }
方案2:使用可读性更高的for...of实现串行上传
reduce处理异步逻辑的可读性和可维护性较差,替换为for...of写法可以大幅降低出错概率:
const imageField = ["logoUrl", "fullLogoUrl"] const onCreate = async (submitData: any) => { const uploadImageField: Record<string, string> = {} for (const field of imageField) { const url = await uploadImage(submitData.general[field][0]) uploadImageField[field] = url } console.log(uploadImageField); }
方案3:使用Promise.all并行上传提升性能
如果上传任务不需要严格按顺序执行,可以用并行上传缩短整体耗时:
const imageField = ["logoUrl", "fullLogoUrl"] const onCreate = async (submitData: any) => { // 批量生成上传任务 const uploadTasks = imageField.map(async field => { const url = await uploadImage(submitData.general[field][0]) return [field, url] as const }) // 等待所有任务完成后转换为对象 const uploadImageField = Object.fromEntries(await Promise.all(uploadTasks)) console.log(uploadImageField); }
内容的提问来源于stack exchange,提问作者PanchaLawther
相关产品推荐
相关产品推荐

