web-dev-qa-db-ja.com

コンストラクターで非同期関数を呼び出します。

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());
     }
 }
6
hashbytes

これは このよくある質問 に関連する問題です。

コードが非同期になると、同期的に使用することはできません。 raw promiseの使用が不要な場合は、すべての制御フローをasync関数で実行する必要があります。

ここでの問題は、getUserがユーザーデータ自体ではなく、ユーザーデータの約束を提供することです。コンストラクターでpromiseが失われ、これはアンチパターンです。

この問題を解決する1つの方法は、IdpServerの初期化の約束を提供することですが、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に依存するすべてのユニットが準備ができるまで初期化されないことを保証します。

もう1つの方法は、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があると予想されます。

11
Estus Flask