为何无法从Object获取键值?Axios异步赋值异常求助
我使用以下代码执行Axios请求并将结果存入myObject变量:
const myObject = {} Object.entries(keysParameter).map((entry, index) => { axios .get(url) .then((res) => { myObject[entry[1].value] = res.data.data }); })
执行console.log(myObject)时,控制台展开后显示结果符合预期:
{ "A": [ "", "AA", "BB" ], "B": [ "AA", "BB" ] }
但调用Object.keys(myObject)返回空数组[],myObject.hasOwnProperty("A")返回false,JSON.parse(JSON.stringify(myObject))返回{} [[Prototype]]: Object。预期Object.keys(myObject)应该返回["A", "B"],请问这是为什么?
核心原因:异步操作的时序问题
代码里的axios.get是异步HTTP请求,map循环会立即触发所有请求,但请求的回调函数(then里的逻辑)要等服务器响应后才会执行。当你调用Object.keys、hasOwnProperty这些方法时,所有请求还没完成,myObject此时还是初始的空对象,自然返回空数组或false。console.log的“惰性求值”误导
浏览器控制台对对象采用惰性求值策略:你执行console.log(myObject)时,对象确实是空的,但当你在控制台展开这个对象时,浏览器会重新读取对象的当前状态——这时候请求已经完成,属性已经被添加,所以你看到的是更新后的结果。验证方式
把对myObject的操作放到then回调里,就能看到真实状态:axios.get(url).then((res) => { myObject[entry[1].value] = res.data.data console.log(Object.keys(myObject)) // 每次请求完成后打印,能逐步看到新增的键 });正确的解决方案
使用Promise.all等待所有异步请求完成后,再操作myObject:const myObject = {} // 收集所有请求的Promise实例 const requestPromises = Object.entries(keysParameter).map((entry) => { return axios.get(url).then((res) => { myObject[entry[1].value] = res.data.data }) }) // 等待所有请求完成后再访问myObject Promise.all(requestPromises).then(() => { console.log(Object.keys(myObject)) // ["A", "B"] console.log(myObject.hasOwnProperty("A")) // true console.log(JSON.parse(JSON.stringify(myObject))) // 预期的完整对象 })如果你在async函数中,也可以用
await简化:async function fetchData() { const myObject = {} const requestPromises = Object.entries(keysParameter).map(async (entry) => { const res = await axios.get(url) myObject[entry[1].value] = res.data.data }) await Promise.all(requestPromises) // 这里可以安全访问myObject console.log(Object.keys(myObject)) } fetchData()
内容的提问来源于stack exchange,提问作者Grandad36

