Зачем fetch не отклоняет promise при статусе Not OK?

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для эффективной обработки ошибок в fetch следует контролировать свойство response.ok. Если его значение — false, следует генерировать исключение. Пример проверки выглядит следующим образом:

JS
Скопировать код
fetch('url')
  .then(response => {
    if (!response.ok) throw new Error(response.statusText); // Если статус ответа не OK, генерируем исключение
    return response.json();
  })
  .catch(error => console.error("Возникла ошибка при выполнении Fetch:", error));

Сначала выполняем проверку статуса ответа, затем в случае обнаружения ошибки генерируем исключение, после чего перехватываем данное исключение для его последующей обработки. Просто и логично.

Кинга Идем в IT: пошаговый план для смены профессии

Обработка различных HTTP-статусов

Приведённый выше метод оптимален для простой обработки ошибок. Вместе с тем, иногда необходимо учитывать конкретные HTTP-статусы и разрабатывать различные сценарии их обработки. Иными словами, подготовить следующий пример:

JS
Скопировать код
function handleErrors(response) {
  if (!response.ok) {
    var error = new Error(response.statusText);
    error.response = response;
    throw error;  // Не стоит избегать генерации исключения
  }
  return response;
}

fetch(url)
  .then(handleErrors)
  .then(response => response.json())
  .catch(error => console.error('Ошибка в результате выполнения Fetch:', error));

Пример с неудачным прохождением авторизации

Если запрос авторизации возвращает статус 401, можно перенаправить пользователя на страницу для входа в систему или выдать ему предупреждающее сообщение.

Пример с отсутствием ресурса

При получении от сервера статуса 404 подойдет специальное сообщение об ошибке или же перенаправление пользователя на страницу поиска.

Пример с ошибкой сервера

С ошибками сервера, кодируемыми статусом 5XX, стоит рассмотреть возможность повторного отправления запроса или об информировании пользователя с просьбой повторить попытку позднее.

Визуализация

Представим обработку ответов fetch в виде контроля качества на ленте производства:

Markdown
Скопировать код
'fetch(url)': [📦, 📦, 📦, 📦] // Каждая коробка представляет собой ответ

Контроль качества: Мы проверяем каждую коробку (ответ)

JS
Скопировать код
if (!response.ok) throw new Error('🔴'); // Отбраковываем некачественный продукт
return response; // Принимаем качественный продукт

А управлять процессом проще всего через .then() и .catch():

JS
Скопировать код
fetch(url)
  .then(response => {
    if (!response.ok) throw new Error('🔴'); // Отбраковываем некачественную коробку
    return response;
  })
  .then(data => console.log('📦✅')) // Допускаем качественные коробки дальше
  .catch(error => console.log('🔴⛔')); // Сортируем бракованные коробки

📦✅ = Получаем правильный ответ
🔴⛔ = Обрабатываем ошибочный ответ

Аналогия поможет запомнить: мы отсеиваем некачественные коробки, передавая далее только качественные.

Применение Async/await для повышения читаемости кода

Синтаксис async/await обеспечивает более структурированный и понятный код, дающий ощущение его последовательного исполнения:

JS
Скопировать код
async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(response.statusText); // Если статус не OK, вызываем исключение сразу
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Fetch завершился с ошибкой:', error);
  }
}

Более удобное управление через try-catch

Используя структуру try-catch, упрощаем управление ошибками, делая код более подобным на синхронный.

Повышенная читаемость

Избегая использования цепочек .then(), переместив обработку ошибок в catch, улучшаем визуальное восприятие кода, что особенно важно при решении сложных задач.

Облегченное управление ошибками

Выбрасывание исключения в try автоматически приводит к отмене промиса, который затем можно обработать в catch.

Универсальная обработка ошибок

Создание общей системы для обработки ошибок предполагает применение единого подхода или функций для однообразного реагирования на различные ответы.

JS
Скопировать код
function errorHandler(status) {
  switch (status) {
    case 400:
      return 'Недопустимый запрос';
    case 401:
      return 'Нет авторизации. Перенаправляем на страницу входа...';
    case 404:
      return 'Ресурс отсутствует. Возможно, его удалили или переместили.';
    // ... Дальнейшие случаи по необходимости
    default:
      return 'Возникла неизвестная ошибка. Пожалуйста, попробуйте еще раз позже.';
  }
}

fetch(url)
  .then(response => response.ok ? response.json() : Promise.reject(errorHandler(response.status)))
  .catch(error => console.error(error));

Связывая конкретные сообщения с различными HTTP-кодами, мы улучшаем информирование пользователей. Данный метод гарантирует, что мы способны реагировать на заранее известные проблемы, а также на непредвиденные события, обеспечивая масштабируемость системы и упрощая добавление новых сценариев обработки.

Полезные материалы

  1. Использование Fetch API – Веб API | MDN — Детальная информация о Fetch API для отправки HTTP-запросов.
  2. Promise – JavaScript | MDN — Методы управления ошибками с использованием промисов в JavaScript.
  3. Управление ошибками HTTP-ответов с помощью fetch() — Стратегии обработки статусов ошибок HTTP в fetch.
  4. Как использовать Fetch API JavaScript для получения данных — Руководство по использованию Fetch API JavaScript для извлечения данных.
  5. ES6 Promises подробно — Обстоятельный анализ промисов ES6 и способов их применения.
  6. Как использовать промисы – Учим веб-разработку | MDN — Введение в основные принципы и преимущества промисов в асинхронном JavaScript.
  7. PromiseRejectionEvent – Веб API | MDN — О том, что такое PromiseRejectionEvent и как работать с отклоненными промисами.