Попадем ли в catch при ошибке в асинхронном вызове внутри try в JavaScript
Что проверяют
Понимаете ли вы, что try...catch ловит только то, что выброшено в его собственном кадре стека, и умеете ли отличать отложенный вызов от ожидаемого. Вопрос дешёвый на словах и почти всегда выявляет тех, кто оборачивает в try всё подряд и считает, что теперь ошибок не будет.
Как отвечать
Ответ начинается с уточнения: зависит от того, как устроен асинхронный вызов.
- есть
awaitвнутриtry: отказ промиса попадёт вcatch, потому чтоawaitвозвращает выполнение в тот же кадр, где стоитtry; - промис без
await: не попадёт. Блокtryзавершится синхронно, раньше чем промис отклонится, и отказ уйдёт в глобальный обработчикunhandledrejection; - колбэк таймера или обработчик события: не попадёт никогда, колбэк исполняется позже и в другом стеке. Нужен свой
tryвнутри колбэка; - колбэк в стиле
(err, data): ошибка приходит аргументом, выбрасывать её некому.
async function load() {
try {
const data = await getData(); // отказ поймается
Promise.reject(new Error("x")); // а этот мимо
setTimeout(() => { throw new Error("x"); }); // и этот мимо
return data;
} catch (e) { report(e); }
}Стоит добавить, что catch в цепочке промисов и try вокруг await это одно и то же, записанное по-разному, и что Promise.allSettled нужен, когда падение одной ветки не должно рушить остальные.
Где спотыкаются
Забывают await и получают функцию, которая никогда не бросает. Ошибка тихо уходит в необработанный отказ, интерфейс просто не показывает данные, а в логе ничего нет. Линтер с правилом на плавающие промисы закрывает почти все такие случаи.
Второе: пишут return getData() внутри try. Локальный catch отказ не увидит, он улетит наружу вызывающему. Чтобы ошибка обрабатывалась здесь, нужен return await getData(), и это единственное место, где return await не лишний.
Третье: думают, что fetch бросает на четырёхсотых и пятисотых кодах. Он отклоняется только на сетевой ошибке, а ответ со статусом 500 считается успешным. Без проверки response.ok блок catch остаётся пустым, а дальше по коду разбирается тело страницы ошибки.