并行等待一次承诺

时间:2019-06-05 15:06:22

标签: javascript react-native

我有一些服务器API方法,它们是在我的应用程序启动时在不同位置调用的,无法根据调用位置进行重构,例如getSettings()getSchedule()。两种方法都基于login(): Promise<Account>方法,设置和计划都是基于用户的。

现在我已经像下面这样解决了getSettings()getSchedule()的开头:

class UserFunctions {
    private fetch_login: Promise<AccountItem> = undefined;
    async getSchedule(): Promise<any> {
        var account = getAccount();
        if (!account) {
            // No account loaded
            let isLogginIn = this.fetch_login;
            if (!this.fetch_login) {
                // Not logging in from any parallel method
                this.fetch_login = login();
            }
            account = await this.fetch_login;
            this.fetch_login = undefined;
        }

        // Now get schedule...
    }
}

其背后的想法是login()函数仅被调用一次,无论它被调用的频率如何。这就是为什么我会在Promise上保留多次引用的原因。此方法有效,但我注意到有时login()完成后getSettings()可以继续工作,并且getSchedule()停留几秒钟直到它继续执行。有时是另一回事,有时两个方法会同时返回。

我在这里打印输出:

  

06-05 16:46:08.126 27376 27397我ReactNativeJS:重新登录

     

06-05 16:46:08.690 27376 27397我ReactNativeJS:重新登录

     

06-05 16:46:08.696 27376 27397 I ReactNativeJS:时间表已下载

     

06-05 16:46:09.274 27376 27397我ReactNativeJS:重新登录

您是否知道一旦login()完成后,两种方法都能继续工作,如何改进代码?

2 个答案:

答案 0 :(得分:1)

我认为您有一个正确的主意,但是逻辑上需要一些调整:

    var account = getAccount();
    if (!account) {
        // No account loaded            
        if (!this.fetch_login) {
            // Not logging in from any parallel method
            this.fetch_login = login();
        }
        account = await this.fetch_login;
    }

基本上,您的想法是将fetch_login设置为在首次调用诺言时具有诺言的值。之后,您可以根据需要await多次进行相同的承诺。

答案 1 :(得分:0)

两件事:

  1. 您正在正在呼叫 fetch_login。您应该只是在引用它:

    account = await this.fetch_login; // <== No ()
    
  2. 删除此行:

    this.fetch_login = undefined;
    

例如:

async getSchedule(): Promise<any> {
    var account = getAccount();
    if (!account) {
        // No account loaded
        if (!this.fetch_login) {
            // Not logging in from any parallel method
            this.fetch_login = login();
        }
        account = await this.fetch_login;
    }

    // Now get schedule...
}

保留登录尝试产生的承诺,因此您可以每次await。 (await作出承诺不会阻止您再次这样做。)


不过,似乎应该在getAccountlogin级别上进行处理,而不是在UserFunctions内进行处理。 getAccountlogin似乎是全局的(在您的应用程序或模块或任何其他内部)。我可能会让他们来管理,getAccount返回一个诺言:

var accountPromise = null;

function getAccount() {
    if (!accountPromise) {
        accountPromise = login();
    }
    return accountPromise;
}

然后

async getSchedule(): Promise<any> {
    var account = await getAccount();

    // Now get schedule...
}

示例:

var accountPromise = null;

function getAccount() {
    if (!accountPromise) {
        accountPromise = login();
    }
    return accountPromise;
}

function login() {
    return new Promise(resolve => {
        console.log("Logging in...");
        setTimeout(() => {
            console.log("Logged in");
            resolve({}); // {} = the account
        }, 800);
    });
}

class UserFunctions {
    /*private*/ fetch_login/*: Promise<AccountItem>*/ = undefined;
    async getSchedule()/*: Promise<any>*/ {
        var account = await getAccount();

        // Now get schedule...
        console.log("Got account, getting schedule");
    }
}

// The first time it's used
const u1 = new UserFunctions();
u1.getSchedule(); // Logs in and gets schedule

// The second time it's used
setTimeout(() => {
    const u2 = new UserFunctions();
    u2.getSchedule(); // Gets schedule (already logged in)
}, 2000);