构造函数中调用异步函数的疑问:getUser异步返回值正确性
问题:异步初始化用户状态时,
isLoggedIn()是否总能返回正确值? 先看你提供的代码:
class IdpServer { constructor() { this._settings = { // some identity server settings. }; this.userManager = new UserManager(this._settings); this.getUser(); } async getUser() { this.user = await this.userManager.getUser(); } isLoggedIn() { return this.user != null && !this.user.expired; } } let idpServer = new IdpServer(); export default idpServer;
结论:不能保证总能返回正确值
原因分析:
- 构造函数是同步执行的,当你调用
new IdpServer()时,构造函数会立刻执行完毕——虽然它调用了getUser()这个异步函数,但构造函数并不会等待getUser()里的await操作完成。 - 这意味着,在
this.userManager.getUser()的异步请求完成前,this.user还是未被正确赋值的初始状态(undefined)。如果someOtherClass在这个异步操作完成前调用idpServer.isLoggedIn(),会得到false的结果,但这时候用户可能已经处于登录状态了,只是我们的代码还没拿到异步返回的用户数据而已。
解决方案
这里有两种常见的修复方式,你可以根据业务场景选择:
方案1:显式初始化方法,让调用方等待初始化完成
把异步初始化逻辑从构造函数中抽离,做成单独的init方法,要求使用这个类的代码必须先等待初始化完成,再调用其他方法:
class IdpServer { constructor() { this._settings = { /* some identity server settings. */ }; this.userManager = new UserManager(this._settings); this.user = null; } // 新增显式初始化方法 async init() { this.user = await this.userManager.getUser(); } isLoggedIn() { return this.user != null && !this.user.expired; } } // 使用方式 let idpServer = new IdpServer(); // 必须先等待初始化完成,再导出或使用 await idpServer.init(); export default idpServer;
方案2:让isLoggedIn()自身等待异步操作完成
如果不想让调用方处理初始化逻辑,可以把获取用户数据的Promise保存下来,让isLoggedIn()每次调用时都自动等待这个Promise完成后再判断状态:
class IdpServer { constructor() { this._settings = { /* some identity server settings. */ }; this.userManager = new UserManager(this._settings); // 保存获取用户的Promise,避免重复发起请求 this.userPromise = this.userManager.getUser(); } async isLoggedIn() { // 每次调用都等待用户数据加载完成 const user = await this.userPromise; return user != null && !user.expired; } } let idpServer = new IdpServer(); export default idpServer;
这种方式下,不管someOtherClass什么时候调用isLoggedIn(),都会自动等待用户数据加载完成后返回正确的判断结果。
内容的提问来源于stack exchange,提问作者hashbytes
相关产品推荐
相关产品推荐

