调用OpenWeather API时出现TypeError:无法解构data.main的'temp'属性问题求助
问题分析与解决方案
嘿,我来帮你拆解下你遇到的问题,主要有两个核心原因,咱们一个个说:
1. 地理定位的异步性导致初始请求无效
navigator.geolocation.getCurrentPosition是异步执行的——它不会立刻返回用户坐标,而是等浏览器获取到位置后才会调用successCallback。但你的setInterval在页面加载后100毫秒就开始调用fetchWeather了,这时候大概率successCallback还没执行,latUser[0]和lonUser[0]都是undefined。
这时候你请求API的URL会变成:https://api.openweathermap.org/data/2.5/weather?lat=undefined&lon=undefined&units=metric&appid=xxx
OpenWeather API收到这种无效参数的请求,会返回错误响应,里面根本没有data.main字段,自然就会抛出解构失败的错误。
你说首次运行偶尔正常,只是刚好那次successCallback在100毫秒内完成了而已,这是概率问题,不是必然的。
2. 请求频率过高触发API限流
每100毫秒调用一次API,意味着每秒请求10次,这远远超过了OpenWeather免费版的请求限制(免费版通常是每分钟60次,也就是每秒1次)。很快API就会返回429 Too Many Requests的错误响应,这种响应的JSON里同样没有main字段,导致持续报错刷屏。
修复后的代码
我帮你调整了代码,解决了上面两个问题,还加了错误处理避免控制台爆炸:
/*Geolocation*/ let latUser; let lonUser; const errorCallback = (error) => { console.error("获取位置失败:", error); }; const successCallback = (position) => { latUser = position.coords.latitude; lonUser = position.coords.longitude; // 拿到坐标后再开始定时请求天气,避免无效请求 fetchWeatherRegularly(); }; navigator.geolocation.getCurrentPosition(successCallback, errorCallback); /*Weather*/ const weatherText = document.querySelector(".wtext"); const weatherCelsius = document.querySelector(".wcelsius"); const weatherHumidity = document.querySelector(".whumid"); const weatherIcon = document.querySelector(".weather-icon"); const weather = { apiKey: "*****", fetchWeather: function () { // 先检查坐标是否存在,避免无效请求 if (!latUser || !lonUser) { console.warn("还未获取到用户坐标,跳过本次请求"); return; } fetch( `https://api.openweathermap.org/data/2.5/weather?lat=${latUser}&lon=${lonUser}&units=metric&appid=${this.apiKey}` ) .then((response) => { // 检查响应是否正常,处理限流或其他错误 if (!response.ok) { throw new Error(`API请求失败:${response.status}`); } return response.json(); }) .then((data) => this.displayWeather(data)) .catch((error) => { console.error("获取天气数据失败:", error); // 可以在这里给用户显示错误提示,比如"天气数据加载失败,请稍后重试" }); }, displayWeather: function (data) { const { temp, humidity } = data.main; const { description, icon } = data.weather[0]; weatherText.innerText = description; weatherCelsius.innerText = `${temp}°C`; weatherHumidity.innerText = `Humidity: ${humidity}%`; weatherIcon.innerHTML = `<img src="icons/${icon}.png">`; }, }; // 改为5分钟请求一次(天气数据不会更新这么快),单位是毫秒 function fetchWeatherRegularly() { // 先立刻请求一次 weather.fetchWeather(); // 之后每5分钟请求一次 setInterval(() => { weather.fetchWeather(); }, 5 * 60 * 1000); }
额外建议
- 天气数据的更新频率很低,完全不需要每100毫秒请求一次,5-10分钟一次就足够了,既符合API限制,也能减少不必要的资源消耗。
- 可以在页面上增加加载状态或错误提示,提升用户体验,比如位置获取失败时告诉用户,天气加载失败时显示友好提示。
内容的提问来源于stack exchange,提问作者veréb
相关产品推荐
相关产品推荐

