Как отлавливать ошибки промисов в JavaScript
Что проверяют
Знаете ли вы, где ошибка может потеряться. Вопрос про промисы, но по сути про места, в которых обработчика не оказывается.
Как отвечать
Ошибка в промисе не выбрасывается наружу синхронно, она превращается в отклонение, и поймать её можно только обработчиком: catch в цепочке или try/catch вокруг await.
Где ошибка теряется чаще всего:
- забытый
await: вызов асинхронной функции без ожидания возвращает промис, а исключение внутри становится необработанным отклонением. Внешнийtry/catchего не увидит; - асинхронный колбэк внутри конструктора промиса: исключение, брошенное в
setTimeoutвнутри исполнителя, не превращается в отклонение, промис останется в ожидании навсегда. Отклонять нужно явным вызовом; forEachс асинхронной функцией: обёртка ничего не ждёт, ошибки уходят в пустоту. Нуженfor awaitилиPromise.all;- обработчик события с
async: тот, кто его вызвал, промис не ждёт, поэтому внутри нужен свойtry/catch; catch, который молча глотает: ошибка исчезает вместе с причиной дефекта. Либо обрабатываем осмысленно, либо пробрасываем дальше.
Страховочная сетка нужна всегда: в браузере это событие unhandledrejection, в Node обработчик того же события на процессе. Обычно оттуда отправляют ошибку в систему сбора, чтобы такие случаи были видны, а не исчезали в консоли пользователя.
Полезно добавить: finally не меняет результат и годится для снятия индикатора загрузки, а собственные классы ошибок помогают отличать сетевую проблему от бизнес-отказа в одном catch.
Где спотыкаются
Пишут try/catch вокруг вызова без await и уверены, что защитились.
Ловят ошибку и логируют её в консоль, из-за чего проблема не видна в мониторинге.
Не различают отклонение промиса и синхронное исключение, из-за чего часть путей остаётся без обработки.