React与JavaScript中返回数据的异步问题
问题解决:异步图片缩放导致dispatch payload为Promise的问题
核心问题
你当前的问题根源在于:map回调使用了async关键字,导致responseImages变成了Promise数组,而非预期的普通对象数组。同时getThumbnail本身是异步函数,必须通过await才能拿到最终的缩略图数据,直接返回的话只会得到Promise实例。
解决方案
不需要修改getThumbnail函数(它的异步逻辑是合理的,毕竟图片加载、画布处理都是异步/耗时操作),只需调整Action中的代码逻辑,等待所有缩略图处理完成后再执行dispatch:
- 用
Promise.all等待responseImages数组中所有Promise完成,获取真正的处理后对象数组 - 修复
photoGroups.forEach(async...)的问题:forEach不会等待内部异步操作完成,换成Promise.all结合map,既保留分组并行的逻辑,又能确保异步操作被正确等待 - 确保将处理完成的
responseImages作为payload dispatch出去(原代码仅定义了变量,未执行dispatch,需补充)
修改后的代码示例
Action.js 关键部分修改
export const uploadPhotos = ({ photos, size, controller }) => async (dispatch) => { // 前面的分组逻辑保持不变 const keyedphotos = photos.map((photo) => [ photo.imageFileName.replace(/-\w+\.\w+$/, ""), photo, ]); const map = new Map(keyedphotos.map(([key]) => [key, []])); for (const [key, photo] of keyedphotos) map.get(key).push(photo); const photoGroups = [...map.values()]; let index = 0; // 替换forEach为Promise.all + map,确保异步操作被正确等待 await Promise.all(photoGroups.map(async (photos) => { // 组内图片保持顺序执行 for (const photo of photos) { const id = index++; const formData = new FormData(); formData.append(photo?.imageFileName, photo?.imageFile); dispatch({ type: constants.UPLOAD_PHOTOS_START, size }); try { const response = await axios.post( `${API_URL}/photos/upload`, formData, { onUploadProgress({ loaded, total }) { dispatch(setUploadProgress({ id, loaded, total })); }, signal: controller.signal, } ); dispatch({ type: constants.UPLOAD_PHOTOS_SUCCESS, payload: response.data, }); // 用Promise.all等待所有缩略图生成完成 const responseImages = await Promise.all(response?.data?.map(async (image) => { // 匹配对应原始图片文件 const matchedImage = photos.find((img) => img?.imageFileName === image?.mediaCode); // 空值兜底,避免getThumbnail报错 if (!matchedImage?.imageFile) { return { productName: image?.uploadResult?.productTitle, imageFile: null, imageFileName: image?.mediaCode || "", }; } // 等待缩略图生成 const thumbnail = await getThumbnail( matchedImage.imageFile, { thumbWidth: 100, thumbHeight: 100, bgColor: "black", } ); return { productName: image?.uploadResult?.productTitle, imageFile: thumbnail, imageFileName: image?.mediaCode || "", }; }) || []); // 补充dispatch,发送处理完成的缩略图数组 dispatch({ type: constants.UPLOAD_PHOTOS_THUMBNAIL_SUCCESS, // 可自定义action type payload: responseImages, }); } catch (error) { dispatch({ type: constants.UPLOAD_PHOTOS_FAILURE, payload: error, }); } } })); };
额外说明
getThumbnail无需修改:它的异步逻辑是必要的,图片加载、画布绘制都依赖异步流程,使用async/await是正确实现- 空值处理:增加了匹配不到图片时的兜底逻辑,避免
getThumbnail接收null参数报错 - 分组异步处理:原forEach无法等待内部异步操作,换成
Promise.all(photoGroups.map(...))后,能确保所有分组的上传、缩略图处理完成后,整个uploadPhotos函数才会结束
内容的提问来源于stack exchange,提问作者Joseph
相关产品推荐
相关产品推荐

