空气质量API出现Uncaught (in promise) TypeError错误,求解决方案
问题:API返回数据缺失导致「Cannot read properties of undefined (reading 'v')」错误
我正在使用空气质量指数(AQI)API实现用户搜索城市获取对应空气质量数据的功能,但部分城市的API返回数据缺少部分监测指标(如臭氧浓度),导致代码执行时出现「Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'v')」错误,相关代码如下:
function retrieveAirQuality(topResultUrl) { var airQualityAPIUrl = "http://api.waqi.info/feed/"+topResultUrl+"/?token="+airQualityAPIToken; fetch(airQualityAPIUrl) .then(function(response) { return response.json(); }) .then(function(data) { if(data.status === "ok") { // Saves air quality results to variable var airQualityResult = { aqi: data.data.aqi, name: data.data.city.name, iaqi: data.data.iaqi, date: data.data.time } renderAirQuality(airQualityResult); } }) } function renderAirQuality(airQuality) { stationNameEl.textContent = "Station Name: " + airQuality.name + " on " + airQuality.date.s; var aqi = document.createElement("tr"); aqi.innerHTML = "<th>Air Quality Index</th><td>"+airQuality.aqi+"</td>" airQualityTableCellEl.appendChild(aqi); var humidity = document.createElement("tr"); humidity.innerHTML = "<th>Humidity</th><td>"+airQuality.iaqi.h.v+"</td>" airQualityTableCellEl.appendChild(humidity); var oz = document.createElement("tr"); oz.innerHTML = "<th>Ozone</th><td>"+airQuality.iaqi.o3.v+"</td>" //Error here airQualityTableCellEl.appendChild(oz); var pressure = document.createElement("tr"); pressure.innerHTML = "<th>Atmospheric Pressure</th><td>"+airQuality.iaqi.p.v+"</td>" airQualityTableCellEl.appendChild(pressure); var pm25 = document.createElement("tr"); pm25.innerHTML = "<th>PM2.5</th><td>"+airQuality.iaqi.pm25.v+"</td>" airQualityTableCellEl.appendChild(pm25); var co = document.createElement("tr"); co.innerHTML = "<th>Carbon Monoxide</th><td>"+airQuality.iaqi.co.v+"</td>" airQualityTableCellEl.appendChild(co); }
解决方案
错误核心是直接访问了可能不存在的嵌套属性(比如airQuality.iaqi.o3.v),当API返回的iaqi中没有对应指标字段时,层级属性会变成undefined,再访问.v就会抛出TypeError。以下是几种实用修复方式:
方式1:可选链操作符(?.)+ 默认值
使用ES6+的可选链操作符?.安全访问嵌套属性,配合??设置默认值(比如显示"N/A"表示无数据),修改renderAirQuality函数:
function renderAirQuality(airQuality) { stationNameEl.textContent = "Station Name: " + airQuality.name + " on " + airQuality.date.s; var aqi = document.createElement("tr"); aqi.innerHTML = "<th>Air Quality Index</th><td>"+airQuality.aqi+"</td>" airQualityTableCellEl.appendChild(aqi); var humidity = document.createElement("tr"); humidity.innerHTML = "<th>Humidity</th><td>"+(airQuality.iaqi.h?.v ?? "N/A")+"</td>" airQualityTableCellEl.appendChild(humidity); var oz = document.createElement("tr"); oz.innerHTML = "<th>Ozone</th><td>"+(airQuality.iaqi.o3?.v ?? "N/A")+"</td>" airQualityTableCellEl.appendChild(oz); var pressure = document.createElement("tr"); pressure.innerHTML = "<th>Atmospheric Pressure</th><td>"+(airQuality.iaqi.p?.v ?? "N/A")+"</td>" airQualityTableCellEl.appendChild(pressure); var pm25 = document.createElement("tr"); pm25.innerHTML = "<th>PM2.5</th><td>"+(airQuality.iaqi.pm25?.v ?? "N/A")+"</td>" airQualityTableCellEl.appendChild(pm25); var co = document.createElement("tr"); co.innerHTML = "<th>Carbon Monoxide</th><td>"+(airQuality.iaqi.co?.v ?? "N/A")+"</td>" airQualityTableCellEl.appendChild(co); }
?.会在属性不存在时返回undefined,??则在左侧为undefined或null时使用默认值,既避免报错又保证页面显示友好。
方式2:提前判断属性是否存在
如果需要兼容不支持可选链的旧环境,可手动逐层判断属性是否存在:
function renderAirQuality(airQuality) { stationNameEl.textContent = "Station Name: " + airQuality.name + " on " + airQuality.date.s; var aqi = document.createElement("tr"); aqi.innerHTML = "<th>Air Quality Index</th><td>"+airQuality.aqi+"</td>" airQualityTableCellEl.appendChild(aqi); // 湿度判断 var humidityVal = airQuality.iaqi.h && airQuality.iaqi.h.v ? airQuality.iaqi.h.v : "N/A"; var humidity = document.createElement("tr"); humidity.innerHTML = "<th>Humidity</th><td>"+humidityVal+"</td>" airQualityTableCellEl.appendChild(humidity); // 臭氧判断 var ozVal = airQuality.iaqi.o3 && airQuality.iaqi.o3.v ? airQuality.iaqi.o3.v : "N/A"; var oz = document.createElement("tr"); oz.innerHTML = "<th>Ozone</th><td>"+ozVal+"</td>" airQualityTableCellEl.appendChild(oz); // 气压判断 var pressureVal = airQuality.iaqi.p && airQuality.iaqi.p.v ? airQuality.iaqi.p.v : "N/A"; var pressure = document.createElement("tr"); pressure.innerHTML = "<th>Atmospheric Pressure</th><td>"+pressureVal+"</td>" airQualityTableCellEl.appendChild(pressure); // PM2.5判断 var pm25Val = airQuality.iaqi.pm25 && airQuality.iaqi.pm25.v ? airQuality.iaqi.pm25.v : "N/A"; var pm25 = document.createElement("tr"); pm25.innerHTML = "<th>PM2.5</th><td>"+pm25Val+"</td>" airQualityTableCellEl.appendChild(pm25); // 一氧化碳判断 var coVal = airQuality.iaqi.co && airQuality.iaqi.co.v ? airQuality.iaqi.co.v : "N/A"; var co = document.createElement("tr"); co.innerHTML = "<th>Carbon Monoxide</th><td>"+coVal+"</td>" airQualityTableCellEl.appendChild(co); }
通过&&运算符逐层验证属性存在性,只有当所有层级属性都有效时才取值,否则用默认值替代。
方式3:封装工具函数简化判断
如果指标较多,可封装工具函数统一处理安全取值逻辑,减少重复代码:
// 工具函数:安全获取嵌套属性,不存在则返回默认值 function getSafeValue(obj, path, defaultValue = "N/A") { return path.split('.').reduce((current, key) => { return current && current[key] ? current[key] : defaultValue; }, obj); } function renderAirQuality(airQuality) { stationNameEl.textContent = "Station Name: " + airQuality.name + " on " + airQuality.date.s; var aqi = document.createElement("tr"); aqi.innerHTML = "<th>Air Quality Index</th><td>"+airQuality.aqi+"</td>" airQualityTableCellEl.appendChild(aqi); var humidity = document.createElement("tr"); humidity.innerHTML = "<th>Humidity</th><td>"+getSafeValue(airQuality.iaqi, 'h.v')+"</td>" airQualityTableCellEl.appendChild(humidity); var oz = document.createElement("tr"); oz.innerHTML = "<th>Ozone</th><td>"+getSafeValue(airQuality.iaqi, 'o3.v')+"</td>" airQualityTableCellEl.appendChild(oz); var pressure = document.createElement("tr"); pressure.innerHTML = "<th>Atmospheric Pressure</th><td>"+getSafeValue(airQuality.iaqi, 'p.v')+"</td>" airQualityTableCellEl.appendChild(pressure); var pm25 = document.createElement("tr"); pm25.innerHTML = "<th>PM2.5</th><td>"+getSafeValue(airQuality.iaqi, 'pm25.v')+"</td>" airQualityTableCellEl.appendChild(pm25); var co = document.createElement("tr"); co.innerHTML = "<th>Carbon Monoxide</th><td>"+getSafeValue(airQuality.iaqi, 'co.v')+"</td>" airQualityTableCellEl.appendChild(co); }
工具函数getSafeValue通过遍历属性路径逐层检查,最终返回对应值或默认值,让代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Frances Cortuna
相关产品推荐
相关产品推荐

