Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чому try...catch не ловить помилку з колбека setTimeout чи обробника події?

try...catch ловить лише помилки, що виникають під час виконання блоку try - поки цей код на стеку викликів.

try {
  setTimeout(() => {
    null.x;   // помилка тут
  }, 0);
} catch (error) {
  console.log('спіймано');   // НЕ виконається
}

Чому: setTimeout лише реєструє колбек і одразу повертає керування. Блок try завершується без помилок. Колбек виконується пізніше, з власного стеку, коли цикл подій дійде до таймера. Зовнішнього try на цьому стеку вже немає. Помилка стає необробленою й іде в глобальний обробник window.onerror.

Те саме для:

  • обробників подій (addEventListener);
  • колбеків старих асинхронних API;
  • then-колбеків Promise, якщо не підключено catch.

Як правильно:

1. try всередині колбека:

setTimeout(() => {
  try {
    riskyWork();
  } catch (error) {
    report(error);
  }
}, 0);

2. Перетворити на Promise і використовувати await:

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

try {
  await sleep(100);
  riskyWork();         // тепер у тій самій async-функції - try спрацює
} catch (error) {
  report(error);
}

await «зшиває» асинхронні кроки в одну логічну послідовність: після очікування виконання продовжується всередині того самого try.

3. Але await має бути:

try {
  saveDraft();             // async-функція без await
} catch (error) {          // не спіймає відхилення
}

try {
  await saveDraft();       // спіймає
} catch (error) {
}

4. return з try в async-функції: return fetchData() повертає Promise без очікування - відхилення пройде повз catch цієї функції. return await fetchData() в try - спіймає.

Обробники подій - помилку краще ловити в самому обробнику або загорнути обробники обгорткою:

const safe = (handler) => async (event) => {
  try {
    await handler(event);
  } catch (error) {
    report(error);
    showToast('Щось пішло не так');
  }
};

button.addEventListener('click', safe(onSave));

Загальне правило: помилку можна спіймати лише там, де її очікують. В асинхронному коді очікування - це await чи catch на відповідному Promise.

Докладніше в документації: Керування потоком і обробка помилок

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання