Node.js类实例化时调用异步方法缓存GET请求数据的问题咨询
所有async函数执行后都会返回一个Promise对象,且函数内部碰到await关键字时会立刻暂停执行,先返回pending状态的Promise,等待异步操作完成后再继续执行后续逻辑。
第一段代码运行不符合预期的原因
class GetSomeData { constructor() { this.storedData = ''; this.getData(); // 这里调用异步方法,但constructor不会等待它执行完成 } getData = async () => { const allData = await axios.get(`URL`, config) this.storedData = allData } } let newInstance = new GetSomeData();
constructor本身是同步执行的,调用this.getData()后不会等待axios请求返回,会直接走完初始化流程。你在实例创建后立刻打印storedData时,axios请求还没有完成,this.storedData = allData的赋值逻辑还没触发,所以拿到的是初始的空字符串。如果延迟几秒再打印,就能拿到接口返回的数据。
第二段代码的运行逻辑
class GetSomeData { constructor() { this.storedData = this.getData(); // 这里直接执行一次getData,把返回的Promise赋值给storedData } getData = async () => { const allData = await axios.get(`URL`, config) return allData } } let newInstance = new GetSomeData();
你对这段代码的理解存在误区:this.getData()是在constructor里直接执行的,仅会在实例初始化阶段运行一次,执行后返回的Promise对象会被直接赋值给this.storedData。后续你访问newInstance.storedData时,读取的是已经存在的Promise实例,不会重新触发getData方法执行。
你说能拿到实际返回数据,本质是你读取这个Promise的时候,它已经处于fulfilled状态,你通过await newInstance.storedData或者.then就能拿到接口返回结果,直接同步打印拿到的还是Promise对象,不是原始返回值。
符合需求的标准实现
如果要实现「实例初始化时请求一次、后续可以直接同步拿到缓存数据」,可以参考如下写法:
class GetSomeData { // 初始化方法,外部实例化后需要先await这个方法 async init() { if (this.storedData) return this.storedData; this.storedData = await axios.get(`URL`, config); return this.storedData; } } // 使用方式 const newInstance = new GetSomeData(); await newInstance.init(); // 后续可以直接读取storedData console.log(newInstance.storedData);
如果想实现不需要外部await的自动初始化,也可以直接把缓存的Promise暴露,所有使用方都await这个属性即可,由于Promise只会决议一次,所以接口也只会请求一次,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Clau Maj

