在构造函数中调用异步函数。

13

getUser是一个异步函数吗?如果它需要更长的时间来解析,那么它是否总是会在我的someotherclass中返回正确的值。

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;


// another class 
// import IdpServer from '...'
 class SomeOtherClass {
     constructor() {
        console.log(IdpServer.isLoggedIn());
     }
 }

5
构造函数一般应该用于将对象构造为可用且有效的状态,而不是做大量的工作。 - James Thorpe
1
@JamesThorpe 此外,构造函数用于创建一个对象,它不会承诺创建对象的部分。 - Alexandre Beaudet
我想你需要让客户端代码在检查状态之前await调用getUser() - Pointy
getUser 实际上是做什么的? - Jonas Wilms
2
重复问题:https://dev59.com/vVkT5IYBdhLWcg3wIsEd,https://stackoverflow.com/questions/37351146/asynchronous-data-loading-in-class-constructor/,https://dev59.com/oGAf5IYBdhLWcg3wqUON - Felix Kling
显示剩余4条评论
1个回答

17

这是一个与这个热门问题有关的问题。

一旦代码异步化,就不能以同步的方式使用。如果不想使用原始Promise,则所有控制流都应该使用async函数执行。

问题在于getUser提供了用户数据的Promise,而不是用户数据本身。 Promise在构造函数中丢失,这是反模式。

解决问题的一种方法是为IdpServer提供初始化Promise,而API的其余部分将是同步的:

class IdpServer {
    constructor() {
        ...
        this.initializationPromise = this.getUser(); 
    }

    async getUser() {
        this.user = await this.userManager.getUser();
    }

    isLoggedIn() {
        return this.user != null && !this.user.expired;
    }
}

// inside async function
await idpServer.initializationPromise;
idpServer.isLoggedIn();

根据应用程序的工作方式,IdpServer.initializationPromise 可以在应用程序初始化时处理,以确保所有依赖于 IdpServer 的单元都不会在其准备好之前初始化。

另一种方法是使 IdpServer 完全异步:

class IdpServer {
    constructor() {
        ...
        this.user = this.getUser(); // a promise of user data
    }

    async getUser() {
        return this.userManager.getUser();
    }

    async isLoggedIn() {
        const user = await this.user;
        return user != null && !user.expired;
    }
}

// inside async function
await idpServer.isLoggedIn();

预计所有依赖它的单元也将具有异步 API。


这是新的实现,@estus 这是在一个函数中进行的,该函数至少在应用程序中使用了20个地方。只是在思考是否有更简单的方法,以便需要最小的更改。 - hashbytes
由于这是设计错误,因此应进行重构。如果存在一个 Promise,则应该有一种方法在依赖于此 Promise 的结果的地方链接它。我猜第一种方式需要更少的更改,并且通常更常见。 - Estus Flask
1
只是想让你们知道,我通过将这个作为第一件要运行的事情来修复它,只有当这个解决了,路由器才会呈现页面模板。 - hashbytes
@hashbytes - 你如何测试 Promise 何时解决? - Jason Cheng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接