Нормально ли бросать (throw) внутри async функции?

Где-то читал, что нехорошо кидаться ошибками изнутри async функций — исключения только для совсем кривых ошибочных случаев. Мол, надо только возвращать rejected Promise.

Вожусь с React компонентом, который проходит цепочку асинхронных действий.
Процесс можно остановить кнопкой в любой момент. Для этого использую AbortController() чтобы останавливать асинхронные этапы работы со сторонним SDK или fetch() запросы на бэкенд.

Во многих местах кода, приходится вставлять одинаковые строки, что-то типа
await someAsyncSdkCall();

// не остановили ли?
if (this.isAborted()) {
  return promiseAborted();
}
довольно много раз получается одинаковый код – после каждого асинхронного вызова. Можно было бы сократить до однострочного this.throwIfAborted();

Что правильнее — повторять три строки десятки раз, или кидаться помётом изнутри async функции? Может, есть ещё способ проверять в цепочке асинхронных действий на каждом шаге, не пора ли всё бросить и уйти в отпуск?
  • Вопрос задан
  • 293 просмотра
Пригласить эксперта
Ответы на вопрос 3
SeaInside
@SeaInside
15 лет пилю все эти штуки
Где-то читал, что нехорошо кидаться ошибками изнутри async функций
... надо только возвращать rejected Promise.

В этом `где-то` вас обманули, так как любое возвращаемое из `async` функции значение (да, включая throw) уже обёрнуто в `Promise`.

const foo = async () => { throw new Error('Smth went wrong'); };
const bar = async () => Promise.reject(new Error('Smth went wrong'));

Работают абсолютно одинаково
Ответ написан
@deliro
Идеологически нет ничего плохого в том, чтобы бросить ошибку в async функции. Она корректно разрушит флоу кода, если промис async функции вызывающая сторона await'ит. и не отловила Другое дело, что в JS промис можно не await'ить, бросание эксепшенов довольно дорогое (по времени) и вообще, эксепшены — это те же goto, только чуть более предсказуемые. Лучше кидаться rust-like контейнерами Result[T, E]. К тому же, их можно типизировать в TS, в отличии от эксепшенов
Ответ написан
Комментировать
profesor08
@profesor08 Куратор тега JavaScript
throw бросит исключение, которое ты можешь обработать когда-то там потом, и гарантирует, что все дальнейшее исполнение будет прервано.

reject не бросает исключения и исполнение кода не прервется. Исключение будет выброшено когда-то там потом, когда промис этого захочет.
new Promise((resolve, reject) => {
  reject("reject msg");
  console.log("wtf?????");
})
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы