reduce中await未生效仅获单图,Promise.all报错的技术问题
异步reduce处理图片上传仅生成photo_0字段的问题解决
问题描述
我在数组的map方法中使用async函数,对每个对象的ImagesParagilder数组调用reduce结合await执行uploadImage图片上传操作,期望生成包含多张图片URL的对象,但最终仅得到photo_0字段;尝试用Promise.all包裹reduce时,出现TypeError: object is not iterable错误,不清楚为何console.log未等待reduce执行完成。
代码示例
foldersTreeImagesFiles.map( async (paragliderFolder) => { const pathfolder = pathImagesParaglider + '/' + paragliderFolder.subfolderName; const imagesUrl = await paragliderFolder.ImagesParagilder.reduce( async (UrlsImage, image, index) => { const pathImage = pathfolder + '/' + image; const folderCoulidinary = 'paraglider/' + paragliderFolder.subfolderName; const resu = await uploadImage(pathImage, folderCoulidinary); UrlsImage.name = paragliderFolder.subfolderName UrlsImage[`photo_${index}`] = resu; return UrlsImage }, {}) console.log(imagesUrl); })
数组示例
[ { subfolderName: 'Arcus_Rs', ImagesParagilder: [ 'swing_arcus2rs_slider_arcus6.jpg', 'swing_arcus2rs_slider_arcus7.jpg', 'swing_arcus2rs_slider_arcuslim4.jpg', 'swing_arcus2rs_slider_arcuslime9.jpg' ], color: [ 'swing_arcus2rs_flame.png', 'swing_arcus2rs_lime.png', 'swing_arcus2rs_nightshade.png', 'swing_arcus2rs_ocean.png' ] }, { subfolderName: 'Coden_Pro', ImagesParagilder: [ 'DSC5495.jpg' ], color: [ 'Air.png', 'Earth.png', 'Fire.png', 'Water.png' ] }, { subfolderName: 'Tonic_2', ImagesParagilder: [ 'DSC5349r.jpg', 'DSC6647r.jpg', 'P1044262r.jpg', 'P1044438r.jpg', 'P1044656r.jpg' ], color: [ 'Lind.png', 'Mustard.png' ] } ]
输出结果
{ name: 'Arcus_Rs', photo_0: 'url********' } { name: 'Coden_Pro', photo_0: 'url********' } { name: 'Tonic_2', photo_0: 'url********' }
问题原因
你在reduce里传入的是async函数,这个函数的返回值是Promise对象,而非你修改后的UrlsImage普通对象。第一次迭代后,下一次的UrlsImage参数变成了Promise,直接给Promise赋值name和photo_${index}不会生效,只有第一次迭代的photo_0被正确赋值,后续迭代都没作用到目标对象上。
另外,reduce本身不处理异步逻辑的链式等待,直接用await包裹整个reduce只能等最后一个Promise完成,但中间迭代已经因为参数是Promise而出错。
解决方法
方法一:在reduce中await前一次的Promise结果
每次迭代先await前一个reduce回调返回的Promise,拿到实际对象后再修改:
foldersTreeImagesFiles.map(async (paragliderFolder) => { const pathfolder = pathImagesParaglider + '/' + paragliderFolder.subfolderName; const imagesUrl = await paragliderFolder.ImagesParagilder.reduce(async (prevPromise, image, index) => { // 先拿到上一次迭代的实际对象 const UrlsImage = await prevPromise; const pathImage = pathfolder + '/' + image; const folderCoulidinary = 'paraglider/' + paragliderFolder.subfolderName; const resu = await uploadImage(pathImage, folderCoulidinary); UrlsImage.name = paragliderFolder.subfolderName; UrlsImage[`photo_${index}`] = resu; return UrlsImage; }, Promise.resolve({})); // 初始值包装成Promise,统一类型 console.log(imagesUrl); });
方法二:用map+Promise.all代替reduce(更直观)
比起异步reduce,用map把每个图片转换成上传Promise,等全部完成后再组装成目标对象,逻辑更清晰:
foldersTreeImagesFiles.map(async (paragliderFolder) => { const pathfolder = pathImagesParaglider + '/' + paragliderFolder.subfolderName; const folderCoulidinary = 'paraglider/' + paragliderFolder.subfolderName; // 生成所有上传任务的Promise数组 const uploadPromises = paragliderFolder.ImagesParagilder.map(async (image, index) => { const pathImage = pathfolder + '/' + image; const resu = await uploadImage(pathImage, folderCoulidinary); return { index, url: resu }; }); // 等待所有上传完成 const results = await Promise.all(uploadPromises); // 组装成目标对象 const imagesUrl = { name: paragliderFolder.subfolderName }; results.forEach(({ index, url }) => { imagesUrl[`photo_${index}`] = url; }); console.log(imagesUrl); });
内容的提问来源于stack exchange,提问作者olivier
相关产品推荐
相关产品推荐

