> Попадем ли в catch при ошибке в асинхронном вызове внутри try в JavaScript (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Kaspersky

Стек: JavaScript

> Пример ответа

Короткий ответ

Нет, не всегда. try/catch ловит только синхронные ошибки и ошибки в await-выражениях. Если асинхронный вызов запущен без await (например, somePromise.catch() или setTimeout), ошибка не попадёт в catch - она станет unhandled rejection. Для надёжной обработки используйте await внутри try или цепочку .catch().

Подробное объяснение

Механика try/catch в JavaScript привязана к синхронному стеку вызовов. Когда вы пишете:

JAVASCRIPT
try {
asyncFunction(); // без await
} catch (e) {
// сюда не попадём
}

asyncFunction() возвращает Promise, но сам вызов завершается синхронно. Ошибка внутри асинхронной части возникнет позже, когда стек try уже завершился. Поэтому catch не сработает.

Правильный вариант - await:

JAVASCRIPT
try {
await asyncFunction();
} catch (e) {
// сюда попадём, если asyncFunction вернёт rejected promise
}

await приостанавливает выполнение и передаёт управление в catch при rejection. Это работает и в async функциях, и в top-level await (в модулях).

Исключение - синхронная ошибка внутри самого async-функции до первого await. Она тоже превращается в rejected promise, поэтому await её поймает.

На практике

  • В async функциях всегда используйте try/catch с await, а не с голым вызовом.
  • Для параллельных операций (Promise.all, Promise.allSettled) оборачивайте весь вызов в try/catch - rejection любого из промисов попадёт в catch.
  • Если нужно обработать ошибку без await (например, в обработчике события), используйте .catch() на промисe.
  • Для setTimeout, setInterval, колбэков из event listeners - try/catch внутри колбэка не спасёт, если ошибка происходит асинхронно. Нужен собственный try/catch внутри самого колбэка.

Пример кода

JAVASCRIPT
// ❌ Ошибка не будет поймана
try {
fetch('/api/data');
} catch (e) {
console.log('Не сработает');
}
// ✅ Правильно с await
async function load() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (e) {
console.log('Поймали:', e.message);
}
}
// ✅ Альтернатива без await
fetch('/api/data')
.then(r => r.json())
.catch(e => console.log('Поймали:', e.message));
// ⚠️ Promise.all - тоже ловится
try {
await Promise.all([fetch('/a'), fetch('/b')]);
} catch (e) {
// сработает при rejection любого
}

Как отвечать на собеседовании

Начните с прямого ответа: "Нет, если вызов не обёрнут в await". Затем объясните разницу между синхронной ошибкой и rejection промиса. Приведите пример с await и без. Упомяните, что async функция всегда возвращает Promise, поэтому даже синхронная ошибка внутри неё становится rejection. Если спросят про Promise.all - скажите, что try/catch ловит rejection любого из промисов.

Что проверяет интервьюер

  • Понимание event loop и асинхронности.
  • Знание разницы между throw и rejected promise.
  • Умение работать с async/await и .catch().
  • Понимание, что try/catch - синхронная конструкция.

Типичные ошибки

  • Ожидание, что try/catch поймает ошибку из setTimeout или колбэка.
  • Забывание await перед асинхронным вызовом внутри try.
  • Попытка использовать try/catch вокруг Promise без await в async функции.
  • Непонимание, что ошибка в .then() без .catch() тоже станет unhandled rejection.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью