> Как перехватывать ошибки в промисах и чем это отличается от try-catch (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: витринатв
Стек: JavaScript
> Пример ответа
Короткий ответ
Перехват ошибок в промисах выполняется через метод .catch() или второй аргумент .then(), а также через try/catch в связке с async/await. Главное отличие: try/catch работает только с синхронным кодом и await-выражениями, тогда как .catch() обрабатывает асинхронные rejection'ы на любом этапе цепочки промисов. Для async/await try/catch - это синтаксический сахар над .catch(), но он не ловит ошибки, возникшие после await вне блока.
Подробное объяснение
Промисы имеют два состояния завершения: fulfilled и rejected. Ошибка может возникнуть:
- при создании промиса (в executor-функции);
- в цепочке
.then()- если предыдущий обработчик бросил исключение или вернул rejected-промис; - при использовании
async/await- еслиawait-выражение отклонено.
Механизм перехвата:
.catch(onRejected)- регистрирует обработчик rejection'а для всей цепочки, начиная с текущего промиса. Если ошибка не обработана в одном.catch(), она пробрасывается дальше по цепочке.- Второй аргумент
.then(onFulfilled, onRejected)- ловит ошибку только на текущем шаге, не затрагивая последующие. try/catchсasync/await- работает как синхронныйtry/catch, но только дляawait-выражений внутри блока. Ошибки, возникающие в микрозадачах послеawait(например, вsetTimeout), не перехватываются.
Ключевое отличие: try/catch не может обработать rejection, если промис создан, но не await'ится внутри блока. Например:
JAVASCRIPTtry {Promise.reject(new Error('fail'));} catch (e) {// не сработает - ошибка асинхронная}
Для async/await try/catch - это просто более читаемая альтернатива .catch(), но с нюансом: если внутри try есть несколько await, то catch поймает первую ошибку и прекратит выполнение блока.
На практике
Для цепочек промисов предпочтительнее .catch() в конце цепочки - это гарантирует обработку всех ошибок, включая те, что возникли в обработчиках. Для async/await - try/catch вокруг группы await-выражений, если нужна единая точка обработки. Если нужно обработать ошибку только на конкретном шаге, используйте второй аргумент .then() или отдельный try/catch вокруг одного await.
Важно: если в цепочке промисов нет .catch() и ошибка не обработана, в Node.js это приведёт к падению процесса (unhandledRejection), в браузере - к ошибке в консоли. Для async/await без try/catch - аналогично.
Пример кода
JAVASCRIPT// Цепочка промисовfetch('/api/data').then(res => res.json()).then(data => process(data)).catch(err => console.error('Ошибка в цепочке:', err));// async/await с try/catchasync function load() {try {const res = await fetch('/api/data');const data = await res.json();return process(data);} catch (err) {console.error('Ошибка в async-функции:', err);}}// Разница: try/catch не ловит асинхронную ошибку вне awaittry {Promise.reject(new Error('async fail'));} catch (err) {// не выполнится}// Правильно: использовать .catch() или awaittry {await Promise.reject(new Error('async fail'));} catch (err) {// выполнится}
Как отвечать на собеседовании
Начните с краткого определения: .catch() - метод промиса, try/catch - синтаксическая конструкция. Затем объясните, что для async/await try/catch - это эквивалент .catch(), но с ограничением: он работает только с await-выражениями. Приведите пример, где try/catch не сработает для промиса без await. Упомяните про обработку ошибок в цепочках: .catch() в конце цепочки ловит всё, второй аргумент .then() - только текущий шаг. Завершите практическим советом: для сложных цепочек используйте .catch(), для читаемости - async/await с try/catch.
Что проверяет интервьюер
- Понимание асинхронной природы промисов и отличие от синхронных исключений.
- Умение объяснить, почему
try/catchне ловит rejection безawait. - Знание особенностей обработки ошибок в цепочках
.then(). - Понимание
unhandledRejectionи важность обязательной обработки ошибок. - Способность выбрать правильный инструмент в зависимости от контекста (цепочка vs async/await).
Типичные ошибки
- Утверждение, что
try/catchработает с любым промисом, даже безawait. - Использование
try/catchвокругPromise.reject()в надежде поймать ошибку. - Забывание
.catch()в конце цепочки - ошибка остаётся необработанной. - Попытка использовать второй аргумент
.then()для обработки ошибок всей цепочки - он ловит только ошибки текущего шага. - Путаница между
throwв синхронном коде и rejection в промисах - это разные механизмы, хотяasync/awaitих объединяет.
> Похожие задачи по frontend
Как игнорировать порядок элементов в массивах при сравнении JSON в тестах
Как обрабатывать валидацию JSON схемы с большим количеством полей и вложенных объектов
Какой опыт работы с JavaScript
Что такое NaN и в каких случаях он возникает
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью