Как обрабатывать ошибки в промисах в JavaScript?
frontend разработкаJavaScriptасинхронностьобработка ошибокпромисы
Что проверяют
Понимаете ли вы, что промис не бросает исключение синхронно, и знаете ли, откуда берутся необработанные отклонения.
Как отвечать
Два стиля, оба рабочие:
// цепочка
fetch(url)
.then((r) => { if (!r.ok) throw new HttpError(r.status); return r.json(); })
.then(render)
.catch(showError)
.finally(hideSpinner);
// async/await
try {
const r = await fetch(url);
if (!r.ok) throw new HttpError(r.status);
render(await r.json());
} catch (e) {
showError(e);
} finally {
hideSpinner();
}Что важно назвать:
fetchне отклоняется на кодах 4xx и 5xx. Он отклоняется только при сетевой ошибке, поэтому статус проверяется вручную. Это ловушка номер один;catchловит всё, что выше по цепочке, включая ошибки, брошенные внутриthen. Порядок важен:catchпередthenне поймает ошибку из этогоthen;- второй аргумент
thenобрабатывает отклонение предыдущего звена, но не ошибки самого обработчика успеха. Поэтому обычно предпочитаютcatch; - необработанное отклонение: промис без обработчика ошибок даёт событие
unhandledrejectionв браузере, а в Node может завершить процесс. Глобальный обработчик стоит вешать хотя бы для отправки в систему сбора ошибок; finallyне меняет результат и подходит для снятия индикатора загрузки;- несколько промисов:
Promise.allотклоняется целиком при первой ошибке и не отменяет остальные,Promise.allSettledдожидается всех и отдаёт статусы; - повторный бросок: внутри
catchможно обработать частный случай и бросить дальше, чтобы решение принял вызывающий.
Где спотыкаются
Считают, что fetch сам упадёт на ответе 500.
Забывают await перед вызовом и получают промис вместо значения, а ошибку вообще нигде.
Ставят catch, который молча проглатывает ошибку, и дефект исчезает из виду вместе с причиной.