Как перехватывать ошибки в промисах и чем это отличается от try-catch
Что проверяют
Понимаете ли вы, как ошибка движется по цепочке промисов и почему try/catch без await её не видит. Следом обычно дают код с forEach и async или с Promise.all и просят сказать, что попадёт в консоль.
Как отвечать
Исключение внутри промиса не летит вверх по стеку, а переводит промис в состояние rejected. Отклонение идёт по цепочке и пропускает все then без второго аргумента, пока не встретит обработчик.
.catch(fn): то же, что.then(undefined, fn). Возвращает новый промис: если обработчик вернул значение, цепочка продолжится успешно, если бросил ошибку, отклонение идёт дальше;- второй аргумент
then: ловит ошибку предыдущих звеньев, но не ошибку из первого аргумента того жеthen. Поэтому.then(ok).catch(fail)надёжнее, чем.then(ok, fail); try/catchсawait:awaitразворачивает отклонение в исключение, и его ловит обычный блок. Безawaitвы получаете промис, а не ошибку;finally: выполняется в любом случае и не меняет результат, если сам не бросил ошибку;- групповые методы:
Promise.allотклоняется на первой ошибке, остальные запросы при этом не отменяются.Promise.allSettledждёт всех и возвращает статус каждого,Promise.anyотклоняется сAggregateError, только если упали все; - необработанное отклонение: браузер генерирует событие
unhandledrejection, а Node.js по умолчанию завершает процесс.
Практический вывод: try/catch удобнее, когда шаги идут последовательно и нужна общая обработка. .catch() уместен, когда промис передаётся дальше или нужен запасной результат прямо в выражении: const user = await load().catch(() => null).
Где спотыкаются
Пишут try { return fetchUser() } без await. Функция отдаёт промис наружу, отклонение проходит мимо catch.
Используют array.forEach(async ...) внутри try. forEach не ждёт промисов, и ошибки становятся необработанными. Нужен for...of с await или Promise.all по map.
Бросают ошибку внутри setTimeout в теле new Promise. Промис её не перехватит, отклонять надо явным вызовом reject.