Как избежать "непогашенной ошибки в обещании" с помощью async / await - PullRequest
0 голосов
/ 28 февраля 2019

Следующий код является 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();

Ссылка на Typescript Playground

У меня есть Promise<>, что рано или поздно будетотказаться.У меня есть обработчик, который await сказал обещание.Однако, если отклонение будет быстрее , тогда мой код, ведущий к вызову await, неким глобальным обработчиком ошибок запустит и завершит работу моего приложения, сообщив мне, что у меня возникла необработанная ошибка.Забавный побочный эффект: если я подожду достаточно долго (в моем примере 10 с), он волшебным образом восстановится и вспомнит, что был блок await и catch, и фактически сделает то, что есть в подвохе.

Но в течение этих 10 секунд мой сценарий звучит так: «Мы все умрем!»Режим.Включается какой-то глобальный обработчик ошибок, мое приложение закрывается.

Что я делаю не так?Разве не весь смысл в том, что я не не должен с этим справляться прямо сейчас ?Почему существует даже глобальный обработчик ошибок?

Мой пример из реальной жизни таков:

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

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

Если задача для выполнения падает быстрее, чем я могу показать счетчик, все мое приложение рухнет.И прежде чем прыгнуть и сказать мне, чтобы добавить блок catch, пожалуйста, посмотрите MCVE, это не проблема.Я ловлю исключение из await выше по цепочке вызовов, но сбой происходит до того, как код даже достигнет await.

1 Ответ

0 голосов
/ 28 февраля 2019

Проблема в том, что вы создаете обещание и ничего с ним не делаете (не устанавливаете обработчик ошибок!), Ожидая в то же время другого обещания:

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

Это хорошо -известный антипаттерн: Ожидание более чем одной параллельной операции ожидания

Обычно ваши методы должны принимать значения, а не обещания, но в этом случае это может быть оправдано, если выхочу завернуть обещание.Вы все еще должны немедленно обработать это все же.Правильное решение будет

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