如何用Promise实现map异步执行?我的React代码输出不符合预期
异步map结合Promise.all的问题修复
问题场景
想通过map实现异步批量操作,用了async和Promise.all,但输出顺序和结果都不符合预期。代码、预期输出和实际输出如下:
原代码
// idList是[1,2,3],每个id对应的接口返回total为[2,3,2] useEffect(()=> { countNumFunc(idList) }) const countNumFunc = (idlist) => { let count = 0 Promise.all(idList.map(async (id) => { console.log("id = ", id) getInfoFromDb(id).then((res) => { if(res.data) { count = count + res.data.total console.log("Count = ", res.data.total) } }).catch(error => { console.log("error = ", error) }) })) console.log("Count total = ", count) }
预期输出
id = 1 Count = 2 id = 2 Count = 5 id = 3 Count = 7 Count total = 7
实际输出
id = 1 id = 2 id = 3 Count total = 0 Count = 2 Count = 3 Count = 2
问题原因
- 异步执行顺序错误:
Promise.all里的map函数虽然加了async,但内部用.then处理异步时没有返回这个Promise,导致Promise.all根本没等getInfoFromDb执行完成就继续走同步代码,所以console.log("Count total = ", count)会先执行,此时count还是初始值0。 - 累加方式不可靠:直接在异步回调里修改外部的count变量,多个异步操作同时修改会导致竞态,而且无法保证顺序。
修复方案
useEffect(()=> { countNumFunc(idList) }, [idList]) // 加上依赖项,避免无意义重复执行 const countNumFunc = async (idList) => { try { // 让每个异步操作返回对应的total,Promise.all收集所有结果 const totals = await Promise.all(idList.map(async (id) => { console.log("id = ", id) const res = await getInfoFromDb(id) const currentTotal = res.data?.total || 0 console.log("当前累加值 = ", currentTotal) return currentTotal })) // 所有异步完成后统一累加 const totalCount = totals.reduce((sum, num) => sum + num, 0) console.log("Count total = ", totalCount) return totalCount } catch (error) { console.log("error = ", error) } }
修复说明
- 把
countNumFunc改为async函数,用await等待Promise.all完成,确保后续代码在所有异步操作结束后执行。 - 用
await替代.then处理getInfoFromDb的异步结果,同时返回每个id对应的total值,让Promise.all收集成数组。 - 用
reduce统一累加数组中的值,避免异步修改外部变量的竞态问题。 - 给
useEffect加上idList依赖项,符合React性能优化的最佳实践。
内容的提问来源于stack exchange,提问作者Renee
相关产品推荐
相关产品推荐

