JavaScript中forEach内赋值的dataShops变量外部访问为空是什么原因?
问题原因分析
你遇到的是前端异步编程的典型执行顺序问题,核心原因如下:
Array.prototype.forEach本身没有等待异步回调执行完成的机制,你传入的async回调会被forEach依次触发后,就直接继续执行后续代码,不会等待回调内部的await异步逻辑执行结束。- 你写的MongoDB查询是异步IO操作,在
forEach遍历结束后直接执行外部的console.log(dataShops)和setDataMain时,所有查询请求还未返回结果,dataShops还停留在初始的空数组状态,所以只能拿到空值。 - 循环内部的打印是在异步查询
await拿到结果之后才执行的,此时已经完成了dataShops的拼接操作,所以能看到完整内容,这两处打印的实际执行顺序和你代码书写的顺序是相反的。
修复方案
把forEach替换为map收集所有异步请求的Promise实例,再用Promise.all等待所有异步请求执行完成后再处理结果即可,修改后参考代码如下:
// 函数本身需要加async修饰 const fetchSales = async () => { const dateInitial = moment(dayInitial, 'ddd, D MMM YYYY').format('YYYY-MM-DD') const dateFinal = moment(dayFinal, 'ddd, D MMM YYYY').format('YYYY-MM-DD') try { setIsLoading(true) // 收集所有异步查询的Promise const requestPromises = app.currentUser.customData.lojas.map(async (value) => { const mongo = app.currentUser.mongoClient("mongodb-atlas").db(value.base) return mongo.collection("vendas").find({ data: { $gte: dateInitial, $lte: dateFinal } }, { sort: { data: 1, hora: 1 } }) }) // 等待所有查询返回结果 const allData = await Promise.all(requestPromises) // 扁平化数组合并所有门店的查询结果 const dataShops = allData.flat() if (mounted) { console.log(dataShops) setDataMain(dataShops) } } catch (e) { setError(e) } finally { setRefreshing(false) setIsLoading(false) } }
内容的提问来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

