请问遍历中穿插异步操作怎么处理

下面代码是图片上传业务,有旧图也可以加新图,新图要压缩,是异步
代码描述

阅读 2.4k
2 个回答

很奇怪,你用的压缩图片的插件为什么会是异步的?

不过既然lrz这个压缩图片插件返回的是一个Promise,那何不用async + await来搞。使用同步的方式写异步代码最爽了,伪代码如下:


async forEachAllImages(images) {
    if (this.state.commodityId === undefined) {
        commodityId = data.success.data.data;
    } else {
        commodityId = this.state.commodityId;
    }
    
    for (let item of images) {
        if ('id' in item) {
            // 旧图片
            console.log('旧图片');
            configArr.push({
                method: 'POST',
                url: 'http://139.224.65.179:8080/api/modify_img',
                data: { id: item.id, img_path: item.path }
            });
            file = item.path;
            lineState = true;
        }else {
            // 新图片
            console.log('新图片');
            
            // 压缩图片插件  -- await 会等待这个lrz处理完成后才返回
            const rst = await lrz(item.file, {
                width: 750,
                height: 750,
                quality: 0.5
            })
            
            configArr.push({
                method: 'POST',
                url: 'http://139.224.65.179:8080/api/modify_img',
                data: { prod_info_id: commodityId, img_path: rst.base64 }
            });
            
            lineState = true;
        }
    }
    
    console.log(200, configArr)
    let makeRequest = (config) => axios(config);
    let requests = configArr.map(makeRequest);
    axios.all(requests);
    this.setState({
        isRenderAlert: true,
        alertData: {
            title: '保存成功!',
            ms: 1500,
            end: () => {
                this.props.history.replace('commodity-detail?id='+ commodityId);
            }
        }
    });
}

// 遍历并处理所有图片
forEachAllImages.call(this, this.state.validatorValue.images)

对了,上面是串行压缩的。如果要并行压缩,可以用Promise.all这样做:


async forEachAllImages(images) {
    if (this.state.commodityId === undefined) {
        commodityId = data.success.data.data;
    } else {
        commodityId = this.state.commodityId;
    }
    
    
    for (let item of images) {
        if ('id' in item) {
            // 旧图片
            console.log('旧图片');
            configArr.push({
                method: 'POST',
                url: 'http://139.224.65.179:8080/api/modify_img',
                data: { id: item.id, img_path: item.path }
            });
            file = item.path;
            lineState = true;
        }else {
            // 新图片
            console.log('新图片');
            
            // 压缩图片插件
            configArr.push(lrz(item.file, {
                width: 750,
                height: 750,
                quality: 0.5
            }).then(rst => ({
                method: 'POST',
                url: 'http://139.224.65.179:8080/api/modify_img',
                data: { prod_info_id: commodityId, img_path: rst.base64 }
            }));
            
            lineState = true;
        }
    }
    
    configArr = await Promise.all(configArr)
    
    console.log(200, configArr)
    let makeRequest = (config) => axios(config);
    let requests = configArr.map(makeRequest);
    axios.all(requests);
    this.setState({
        isRenderAlert: true,
        alertData: {
            title: '保存成功!',
            ms: 1500,
            end: () => {
                this.props.history.replace('commodity-detail?id='+ commodityId);
            }
        }
    });
}

// 遍历并处理所有图片
forEachAllImages.call(this, this.state.validatorValue.images)

当然,这个并行版本其实不用async + await也可以写得很简洁:


forEachAllImages(images) {
    if (this.state.commodityId === undefined) {
        commodityId = data.success.data.data;
    } else {
        commodityId = this.state.commodityId;
    }
    
    
    for (let item of images) {
        if ('id' in item) {
            // 旧图片
            console.log('旧图片');
            configArr.push({
                method: 'POST',
                url: 'http://139.224.65.179:8080/api/modify_img',
                data: { id: item.id, img_path: item.path }
            });
            file = item.path;
            lineState = true;
        }else {
            // 新图片
            console.log('新图片');
            
            // 压缩图片插件
            configArr.push(lrz(item.file, {
                width: 750,
                height: 750,
                quality: 0.5
            }).then(rst => ({
                method: 'POST',
                url: 'http://139.224.65.179:8080/api/modify_img',
                data: { prod_info_id: commodityId, img_path: rst.base64 }
            }));
            
            lineState = true;
        }
    }
    
    Promise.all(configArr)
        .then(configArr => {
            console.log(200, configArr)
            let makeRequest = (config) => axios(config);
            let requests = configArr.map(makeRequest);
            axios.all(requests);
            this.setState({
                isRenderAlert: true,
                alertData: {
                    title: '保存成功!',
                    ms: 1500,
                    end: () => {
                        this.props.history.replace('commodity-detail?id='+ commodityId);
                    }
                }
            });
        });
}

// 遍历并处理所有图片
forEachAllImages.call(this, this.state.validatorValue.images)

三个版本任君挑选。

遍历中穿插异步,可以使用对象缓存数据。键名表示处理序列中唯一的ID,键值是处理结果(此处应该是图片摘要数据JS对象),由异步回调函数填入。异步回调函数传参不仅需要传源数据,还要传入在对象中需要回调填回的ID。这样,就可以防止遗漏或者错乱数据了。

如果要确定所有异步操作都做完才进行下一步,就在异步里填完数据之后再检查一遍是否所有的都有数据。

最后,再将对象转换成新的数组,这就是所有图片的信息列表了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题