如何在条件设置对象字段时用Promise.all优化React Native代码
问题描述
我正在开发一个React Native Expo应用。我有一个发起API调用的函数,该调用返回包含多个字段的对象数组。每个对象包含2-4个需要下载并存储到本地的资源。
目前我遍历响应结果,检查每个对象拥有哪些字段,然后调用saveImage函数存储资源,该函数返回新的本地URI,我用它替换原始URL。代码如下:
await axios .get(process.env.EXPO_PUBLIC_URL) .then(async (res) => { for (obj of res.data.entries()) { if (obj.image) { obj.image = await saveImage(obj.image, obj.name, "image") } if (obj.secondaryImage) { obj.secondaryImage = await saveImage(obj.secondaryImage, obj.name, "secondaryImage") } if (obj.logo) { obj.logo = await saveImage(obj.logo, obj.name, "logo") } if (obj.datasheet) { obj.datasheet = await saveImage(obj.datasheet, obj.name, "datasheet") } } await AsyncStorage.setItem("items", JSON.stringify(res.data));
我知道应该使用Promise.all()来提升性能,但仍需保留条件设置存在字段的逻辑。请问如何实现这一点,或者有没有其他优化这段代码的方法?
优化方案
1. 单对象内并行处理资源下载
当前代码串行处理每个对象的资源,效率偏低。可以针对每个对象,收集所有需要执行的saveImage任务(仅处理存在的字段),再用Promise.all()并行执行,让同一对象内的多个资源同时下载,提升处理速度。
代码示例:
await axios.get(process.env.EXPO_PUBLIC_URL) .then(async (res) => { // 并行处理所有对象 await Promise.all(res.data.map(async (obj) => { const tasks = []; // 为存在的字段创建下载任务,完成后更新对象字段 if (obj.image) { tasks.push(saveImage(obj.image, obj.name, "image").then(localUri => { obj.image = localUri; })); } if (obj.secondaryImage) { tasks.push(saveImage(obj.secondaryImage, obj.name, "secondaryImage").then(localUri => { obj.secondaryImage = localUri; })); } if (obj.logo) { tasks.push(saveImage(obj.logo, obj.name, "logo").then(localUri => { obj.logo = localUri; })); } if (obj.datasheet) { tasks.push(saveImage(obj.datasheet, obj.name, "datasheet").then(localUri => { obj.datasheet = localUri; })); } // 等待当前对象的所有下载任务完成 await Promise.all(tasks); })); await AsyncStorage.setItem("items", JSON.stringify(res.data)); });
2. 全局批量并行处理所有资源
如果API返回的对象数量不多,可以把所有对象的所有下载任务收集到一个数组中,用Promise.all()一次性并行执行,效率会进一步提升。但要注意:若对象和资源数量极大,可能触发网络或设备的并发限制,需根据实际情况调整。
代码示例:
await axios.get(process.env.EXPO_PUBLIC_URL) .then(async (res) => { const allTasks = []; res.data.forEach(obj => { if (obj.image) { allTasks.push(saveImage(obj.image, obj.name, "image").then(localUri => { obj.image = localUri; })); } if (obj.secondaryImage) { allTasks.push(saveImage(obj.secondaryImage, obj.name, "secondaryImage").then(localUri => { obj.secondaryImage = localUri; })); } if (obj.logo) { allTasks.push(saveImage(obj.logo, obj.name, "logo").then(localUri => { obj.logo = localUri; })); } if (obj.datasheet) { allTasks.push(saveImage(obj.datasheet, obj.name, "datasheet").then(localUri => { obj.datasheet = localUri; })); } }); await Promise.all(allTasks); await AsyncStorage.setItem("items", JSON.stringify(res.data)); });
3. 额外优化建议
- 错误处理:当前代码未处理
saveImage或API调用的异常,建议添加try/catch块,避免单个资源下载失败导致整个流程中断,可选择跳过失败资源或记录错误日志。 - 保持数据不可变性:若不想直接修改
res.data中的原对象,可以创建新对象存储本地URI,避免副作用。 - 限制并发数:如果资源数量极大,可使用
p-limit(Expo可安装该包)控制同时执行的Promise数量,防止设备性能或网络过载。
内容的提问来源于stack exchange,提问作者Andrei Costin
相关产品推荐
相关产品推荐

