如何通过async / await避免“承诺中未捕获的错误”

时间:2019-02-28 15:10:57

标签: typescript promise async-await

以下代码是我的问题的MCVE:

class MyApp {
    public async crash(): Promise<number> { 
        throw new Error("Hello Error");
    }

    public async chain(promise: Promise<number>) {
        await this.delay(10000);
        return promise;
    }

    private async delay(ms: number): Promise<void> {
       return new Promise<void>( resolve => setTimeout(resolve, ms) );
    }
}

const myApp = new MyApp();

const a = async () => { 
    try {
        const foo = await myApp.chain(myApp.crash());
    } catch (e) {
        console.log("Hello Catch");
    }
};

a();

Link to Typescript Playground

我有一个Promise<>,迟早会拒绝。我有一个处理程序,将await表示诺言。但是,如果拒绝的速度更快,那么我的代码将导致await调用,一些全局错误处理程序将启动并结束我的应用程序,告诉我我有一个未捕获的错误。有趣的副作用:如果我等待足够长的时间(在我的示例中为10秒),它将神奇地恢复,并记住存在一个await和一个catch块,并且实际上可以完成任务。

但是在那10秒钟里,我的剧本是在“我们都会死!”模式。一些全局错误处理程序启动,我的应用程序已关闭。

我在做什么错?我不是async 现在就必须处理 的全部要旨吗?为什么甚至有全局错误处理程序?

我的现实情况是这样的:

public async showWait<T>(promise: Promise<T>): Promise<T> {
    await loadingSpinner.present();

    try {
        return await promise;
    }
    finally {
        await loadingSpinner.dismiss();
    }
}

如果执行任务的崩溃速度比显示微调器快,那么我的整个应用程序将崩溃。在您告诉我添加捕获块之前,请先查看MCVE,这不是问题。我确实从呼叫链上端的await处捕获了异常,但是崩溃发生在之前,代码甚至到达了await

1 个答案:

答案 0 :(得分:4)

问题在于,您正在构造一个承诺,但与此同时不做任何事情(未安装错误处理程序!),同时等待其他承诺:

let promise = crash();
await loadingSpinner.present();
await promise;

这是一个众所周知的反模式:Waiting for more than one concurrent await operation

通常,您的方法应接受值而不是诺言,但是在这种情况下,如果您想包装诺言,则可以保证。您仍然需要立即处理它。正确的解决方案是

public async showWait<T>(promise: Promise<T>): Promise<T> {
    try {
        const [, val] = await Promise.all([
           loadingSpinner.present(),
           promise,
        ]);
        return val;
    } finally {
        await loadingSpinner.dismiss();
    }
}