使用带async回调的forEach时变量赋值错误,如何等待遍历执行完成?
问题原因
Array.prototype.forEach 原生不支持等待异步回调执行完成,你传入的async函数会被批量触发,但forEach不会等待这些异步任务的Promise状态变为完成,直接就执行了后续的赋值逻辑,所以拿到的永远是初始的0值。
解决方法
方案1:并行执行(推荐,性能更高)
把forEach替换为map生成Promise数组,再用Promise.all等待所有异步请求全部执行完成后再做赋值操作:
// 完整修改后的代码 const megaCheck = async (prods) => { let puntosGastados = 0 let stickersGastados = 0 const productos = prods[0].items let host = '' if (window.location.host.split('.')[0].indexOf('wongfoodqawlschv6io') > -1 ) { host = 'wongfoodqawlschv6io' } else if (window.location.host.split('.')[0].indexOf('metroqaio') > -1) { host = 'metroqaio' } // 生成所有请求的Promise数组 const requestPromises = productos.map(async (producto) => { try { const { data } = await axios.get(`/api/catalog_system/pub/products/search?fq=productId:${producto.id}`) if(data[0]["mega-promo"].length){ let megaInfo = JSON.parse(data[0]["mega-promo"]) puntosGastados += (megaInfo.puntos * producto.quantity) stickersGastados += (megaInfo.stickers * producto.quantity) console.log("Puntos gastados --" + puntosGastados) console.log("Stickers gastados --" + stickersGastados) } } catch (error) { console.error(error) } }) // 等待所有请求完成后再执行后续逻辑 await Promise.all(requestPromises) console.log(puntosGastados) console.log(stickersGastados) setMegaUserInfo({ points: puntosGastados, stickers: stickersGastados }) console.log(megaUserInfo) }
方案2:串行执行(适合需要控制并发的场景)
如果接口有并发限制,需要按顺序逐个发起请求,可以用for...of循环代替forEach,每次await当前请求完成后再处理下一个:
// 仅替换遍历部分的代码即可 for (const producto of productos) { try { const { data } = await axios.get(`/api/catalog_system/pub/products/search?fq=productId:${producto.id}`) if(data[0]["mega-promo"].length){ let megaInfo = JSON.parse(data[0]["mega-promo"]) puntosGastados += (megaInfo.puntos * producto.quantity) stickersGastados += (megaInfo.stickers * producto.quantity) console.log("Puntos gastados --" + puntosGastados) console.log("Stickers gastados --" + stickersGastados) } } catch (error) { console.error(error) } }
两种方案的区别:
- 并行方案总耗时等于最慢的那一个请求的耗时,性能更高,适合没有并发限制的场景
- 串行方案总耗时是所有请求耗时的总和,适合接口有请求频率限制的场景
内容的提问来源于stack exchange,提问作者Pablo Gardiazabal
相关产品推荐
相关产品推荐

