基于OpenWeatherAPI的天气应用:Geocode属性调用显示Undefined问题
问题根源:异步操作的执行时机问题
你遇到的这个undefined问题,本质是异步代码的执行顺序导致的:
Geocode类的构造函数里调用了getLatLong()这个异步方法,但构造函数本身不能是异步函数。当你执行new GeoCode("toronto")时,构造函数会立刻完成,但getLatLong里的axios请求还在后台运行——这时候你马上访问geocode.lat和geocode.lon,这两个属性还没被赋值,自然是undefined。而稍后console.log(geocode)时,浏览器/Node.js会异步更新对象的显示,所以你能看到已经赋值后的完整属性。
解决方案:控制异步操作的执行时机
下面提供两种优雅的解决方式,你可以根据自己的代码风格选择:
方案一:给Geocode类添加初始化方法,外部await完成
修改geocode.js:
import axios from "axios"; export default class Geocode{ constructor(city){ this.city = city; // 不在构造函数里直接调用异步方法,把初始化控制权交给外部 } // 新增异步初始化方法 async init(){ try{ const res = await axios(`https://us1.locationiq.com/v1/search.php?key=${key}&q=${this.city}&format=json`); // 用parseFloat替代JSON.parse,更适合处理数字字符串 this.lat = parseFloat(res.data[0].lat); this.lon = parseFloat(res.data[0].lon); }catch(err){ console.log(err) } } }
修改index.js:
用async函数包裹整个应用逻辑,等待Geocode初始化完成后再创建Search实例:
import Search from "./models/search"; import GeoCode from "./models/geocode"; async function initApp() { const geocode = new GeoCode("toronto"); await geocode.init(); // 等待地理编码请求完成,确保lat和lon已赋值 const weather = new Search(geocode.lat, geocode.lon); await weather.getResults(); // 可选:如果需要等待天气请求完成再打印结果 console.log(geocode); console.log(weather); } // 启动应用 initApp();
方案二:使用静态异步工厂方法创建Geocode实例
这种方式更符合异步代码的最佳实践,直接返回一个已经初始化完成的Geocode实例:
修改geocode.js:
import axios from "axios"; export default class Geocode{ // 构造函数只负责赋值,不处理异步逻辑 constructor(city, lat, lon){ this.city = city; this.lat = lat; this.lon = lon; } // 静态异步方法,负责请求数据并创建实例 static async create(city){ try{ const res = await axios(`https://us1.locationiq.com/v1/search.php?key=${key}&q=${city}&format=json`); const lat = parseFloat(res.data[0].lat); const lon = parseFloat(res.data[0].lon); return new Geocode(city, lat, lon); }catch(err){ console.log(err); throw err; // 抛出错误,让外部可以捕获处理 } } }
修改index.js:
import Search from "./models/search"; import GeoCode from "./models/geocode"; async function initApp() { try { // 直接获取已经完成地理编码的实例 const geocode = await GeoCode.create("toronto"); const weather = new Search(geocode.lat, geocode.lon); await weather.getResults(); console.log(geocode); console.log(weather); } catch (err) { console.error("应用初始化失败:", err); } } initApp();
额外优化点
- 你原本用
JSON.parse(res.data[0].lat)是多余的,API返回的经纬度是字符串格式的数字,用parseFloat()更高效准确。 - Search类同样存在异步问题:如果不
await weather.getResults(),直接打印weather的话,result属性也会是undefined,所以建议也等待天气请求完成。
内容的提问来源于stack exchange,提问作者Tidris
相关产品推荐
相关产品推荐

