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

Де ловити помилки у фронтенд-застосунку, а де пропускати їх далі?

Найчастіша проблема з помилками - не відсутність обробки, а обробка не в тому місці: try...catch у кожній функції, де помилку логують і повертають null, а вищий рівень так і не дізнається, що щось пішло не так.

Принцип: ловити там, де знаєш, що робити.

Функція, яка не може осмислено відреагувати на помилку, має пропустити її далі. «Що робити» майже завжди вирішує рівень, близький до користувача.

Шари типового застосунку:

1. Низький рівень (HTTP-клієнт, парсери) - перетворює помилки на зрозумілі типи, але не ховає їх:

async function apiRequest(url, options) {
  const response = await fetch(url, options);
  if (response.status === 422) throw new ValidationError((await response.json()).errors);
  if (response.status === 401) throw new UnauthenticatedError();
  if (!response.ok) throw new HttpError(response);
  return response.json();
}

2. Сервіси й бізнес-логіка - зазвичай не ловлять нічого. Винятки - очікувані ситуації з альтернативною поведінкою: кеш недоступний - читаємо напряму; необов'язкова рекомендація не завантажилася - показуємо сторінку без неї.

3. Межа взаємодії (обробник форми, дія користувача) - тут вирішують, що показати:

async function onSubmit() {
  try {
    await saveOrder(form);
    showToast('Замовлення збережено');
  } catch (error) {
    if (error instanceof ValidationError) return showFieldErrors(error.errors);
    if (error instanceof UnauthenticatedError) return redirectToLogin();
    report(error);                                  // неочікуване - у моніторинг
    showToast('Не вдалося зберегти. Спробуйте ще раз');
  }
}

4. Глобальний рубіж - window.onerror, unhandledrejection, errorHandler фреймворку, error boundary: для того, що проскочило, - звіт у моніторинг і запасний інтерфейс замість білого екрана.

Очікувані й неочікувані помилки:

  • очікувані (валідація, 404 «товар не знайдено», немає прав) - частина звичайного сценарію. Їх обробляють і не надсилають у моніторинг як помилки;
  • неочікувані (TypeError, 500) - баги. Їх показують користувачеві загальним повідомленням і обов'язково звітують.

Змішування призводить до того, що моніторинг завалений тисячами «помилок валідації», а справжній баг тоне в шумі.

Антипатерни:

  • catch (e) { console.log(e) } без подальшої дії - помилка «оброблена», але застосунок у зламаному стані;
  • повернення null/false замість винятку - виклики далі мусять перевіряти результат, і рано чи пізно перевірку забудуть;
  • однакове «Щось пішло не так» для всього - і для помилки валідації, і для недоступного сервера;
  • catch лише для того, щоб throw ту саму помилку - шум.

Альтернатива винятками - тип-результат ({ ok: true, value } / { ok: false, error }), популярний у TypeScript для очікуваних помилок: компілятор змушує обробити обидва варіанти. Але для неочікуваних помилок винятки лишаються природнішими.

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

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