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

Що відбувається з відхиленим Promise без catch і як ловити глобальні помилки?

Якщо Promise відхилено, а обробника помилки (catch, другого аргументу then, try навколо await) немає, помилка стає необробленою.

У браузері сторінка продовжує працювати, але:

  • у консолі з'являється Uncaught (in promise) Error: ...;
  • на window спрацьовує подія unhandledrejection.

У Node.js з версії 15 необроблене відхилення завершує процес з помилкою. Сервер на Node, де забули catch, падає від першого ж збою мережі.

Глобальні обробники в браузері:

// необроблені винятки в синхронному коді й колбеках
window.addEventListener('error', (event) => {
  report({
    message: event.message,
    source: event.filename,
    line: event.lineno,
    stack: event.error?.stack,
  });
});

// необроблені відхилення Promise
window.addEventListener('unhandledrejection', (event) => {
  report({ message: String(event.reason), stack: event.reason?.stack });
  // event.preventDefault() - прибрати повідомлення з консолі
});

event.reason - те, з чим відхилено Promise (зазвичай об'єкт Error, але може бути будь-що).

Подія rejectionhandled спрацьовує, якщо обробник додали пізніше, ніж браузер зафіксував відхилення як необроблене. Буває при «лінивому» підключенні catch.

Що ці обробники дають і чого ні:

  • це останній рубіж для моніторингу, а не спосіб обробляти помилки. Зловити тут помилку й «продовжити» неможливо: функцію, що впала, уже не повернути;
  • саме так працюють Sentry, Flare та інші системи: підписуються на ці події й надсилають звіти на сервер;
  • помилки зі скриптів іншого домену (CDN) приходять як Script error. без деталей - браузер приховує їх з міркувань безпеки. Деталі з'являться, якщо скрипт підключено з crossorigin="anonymous" і сервер віддає заголовок CORS.

Типові джерела необроблених відхилень:

  • fetch(...).then(...) без catch наприкінці ланцюжка;
  • виклик async-функції без await («запустив і забув»): saveDraft(); в обробнику події;
  • Promise.all, у якому відхилився один Promise, - решта відхилень після першого вже ігноруються, але перше має бути оброблене.

Правило: кожен ланцюжок Promise має закінчуватися обробкою помилки, а «запущені й забуті» async-виклики - явним .catch(report). Лінтер (@typescript-eslint/no-floating-promises) знаходить такі місця автоматично.

Докладніше в документації: Подія unhandledrejection

Перевір себе

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

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