You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:05:18