访问JSON对象数组返回undefined的问题排查求助
异步请求导致数组元素访问失败的问题
问题场景
以下代码意图通过fetch获取JSON数据,用扩展运算符把数据推入cities数组后访问数组内容:
<!DOCTYPE html> <html> <head> <title>Practice</title> </head> <body> <script> const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; const cities = []; fetch(endpoint) .then(blob => blob.json()) .then(data => cities.push(...data)); console.log(cities) console.log(cities[0]) console.log(cities[0].city) </script> </body> </html>
实际运行时,console.log(cities)看似显示对象数组,但cities[0]返回undefined,访问cities[0].city抛出错误:
index.html:26 Uncaught TypeError: Cannot read properties of undefined (reading 'city')
预期cities[0]返回{city: 'New York', growth_from_2000_to_2013: '4.8%', latitude:40.7127837, longitude: -74.0059413, population: '8405837', …},cities[0].city返回'New York'。
问题原因
fetch是异步操作,它不会阻塞后续代码执行。当你调用console.log(cities)、console.log(cities[0])这些语句时,fetch的请求还没完成,cities数组还是空的,自然访问不到元素。
至于console.log(cities)看起来有数据,是因为浏览器控制台会惰性求值——当你点开控制台里的数组对象时,请求已经完成,数组被填充了数据,但执行console.log的那一刻数组其实是空的。
解决方法
所有需要用到cities数组数据的代码,必须放在fetch的回调函数里,或者用async/await语法确保等待请求完成后再执行:
方法1:在then回调内处理数据
<!DOCTYPE html> <html> <head> <title>Practice</title> </head> <body> <script> const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; const cities = []; fetch(endpoint) .then(blob => blob.json()) .then(data => { cities.push(...data); // 所有依赖cities的操作都放在这里 console.log(cities) console.log(cities[0]) console.log(cities[0].city) }); </script> </body> </html>
方法2:使用async/await语法
<!DOCTYPE html> <html> <head> <title>Practice</title> </head> <body> <script> const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; async function loadCities() { const cities = []; const response = await fetch(endpoint); const data = await response.json(); cities.push(...data); // 在这里处理数据 console.log(cities) console.log(cities[0]) console.log(cities[0].city) } loadCities(); </script> </body> </html>
内容的提问来源于stack exchange,提问作者SkyCowie
相关产品推荐
相关产品推荐

