Современные веб-приложения постоянно общаются с сервером: загружают данные, отправляют формы, обновляют контент без перезагрузки страницы. За это отвечает асинхронный JavaScript. Долгое время стандартом был XMLHttpRequest, но он громоздкий и неудобный. На смену пришёл Fetch API — простой и мощный инструмент для сетевых запросов. В этой статье разберём, как пользоваться Fetch, обрабатывать ответы, ловить ошибки и применять продвинутые приёмы.

Digital-студия WNDER

Что такое Fetch API и зачем он нужен

Fetch API — это встроенный в браузер интерфейс для выполнения HTTP-запросов. Он основан на промисах, что делает код чище и позволяет избежать ада колбэков. Синтаксис прост: вызываем fetch(url) и получаем промис, который разрешается объектом Response.

В отличие от XMLHttpRequest, Fetch не требует создания экземпляра, настройки обработчиков и вызова send. Всё лаконично:

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

Но это только верхушка айсберга. Fetch умеет гораздо больше: настраивать заголовки, отправлять данные, работать с разными форматами, отменять запросы.

Основы: как выполнить GET-запрос

Самый простой случай — получить данные с сервера. Допустим, у нас есть API, возвращающее список пользователей.

fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => {
    if (!response.ok) {
      throw new Error('Сеть ответила с ошибкой: ' + response.status);
    }
    return response.json();
  })
  .then(users => {
    users.forEach(user => console.log(user.name));
  })
  .catch(error => console.error('Ошибка запроса:', error));

Здесь мы проверяем свойство response.ok — оно истинно, если статус ответа в диапазоне 200-299. Если нет — выбрасываем исключение, которое попадёт в catch. Без этой проверки fetch не считает ошибкой статусы 404 или 500, и мы можем пытаться распарсить невалидный JSON.

Метод response.json() читает тело ответа и преобразует его из JSON в JavaScript-объект. Это асинхронная операция, возвращающая промис.

Правило: Всегда проверяйте response.ok перед обработкой данных. Fetch не отклоняет промис при HTTP-ошибках, поэтому легко пропустить проблему.

Отправка данных: POST, PUT, DELETE

Для отправки данных используется второй аргумент fetch — объект с настройками. В нём указываем метод, заголовки и тело запроса.

const newUser = {
  name: 'Иван',
  email: 'ivan@example.com'
};

fetch('https://jsonplaceholder.typicode.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  },
  body: JSON.stringify(newUser)
})
  .then(response => response.json())
  .then(data => console.log('Успех:', data))
  .catch(error => console.error('Ошибка:', error));

Обратите внимание: тело запроса должно быть строкой. Если отправляем JSON, используем JSON.stringify и устанавливаем заголовок Content-Type: application/json.

Для PUT и DELETE принцип тот же, меняется только метод. DELETE обычно не требует тела.

Метод Назначение Тело запроса
GET Получить данные Нет
POST Создать ресурс Да
PUT Обновить ресурс Да
DELETE Удалить ресурс Обычно нет

Обработка ошибок и асинхронный / await

Промисы удобны, но цепочки .then() могут разрастаться. С появлением async/await код стал ещё читаемее. Fetch отлично с ними сочетается.

async function fetchUsers() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const users = await response.json();
    console.log(users);
  } catch (error) {
    console.error('Ошибка при загрузке:', error);
  }
}

fetchUsers();

Конструкция try/catch позволяет элегантно обрабатывать как сетевые ошибки, так и ошибки парсинга JSON. Не забывайте, что await можно использовать только внутри async-функции.

Fetch также поддерживает отмену запросов через AbortController. Это полезно, если пользователь ушёл со страницы или запрос долго выполняется.

const controller = new AbortController();
const signal = controller.signal;

fetch('https://api.example.com/slow', { signal })
  .then(response => response.json())
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Запрос отменён');
    } else {
      console.error('Ошибка:', error);
    }
  });

// Отменить запрос через 2 секунды
setTimeout(() => controller.abort(), 2000);
Лайфхак: Используйте AbortController для отмены устаревших запросов при быстром переключении между страницами или вводе поискового запроса. Это сэкономит ресурсы и избежит гонок данных.

Продвинутые приёмы и сравнение с XMLHttpRequest

Fetch API не поддерживает прогресс загрузки (upload progress) напрямую, в отличие от XMLHttpRequest. Для отслеживания прогресса отправки файлов приходится использовать другие подходы или библиотеки. Также fetch не отправляет куки по умолчанию для кросс-доменных запросов — нужно указывать credentials: 'include'.

Сравним два подхода в таблице:

Критерий Fetch API XMLHttpRequest
Синтаксис Простой, на промисах Громоздкий, на колбэках
Поддержка прогресса Нет (только через ReadableStream) Есть
Отмена запроса AbortController abort()
Куки по умолчанию Не отправляются Отправляются

Несмотря на некоторые ограничения, Fetch стал стандартом де-факто для сетевых запросов в современном JavaScript. Он лаконичен, мощен и хорошо сочетается с async/await.

Ещё один полезный приём — создание обёртки для fetch, которая автоматически добавляет заголовки, обрабатывает ошибки и возвращает JSON. Это избавит от дублирования кода.

async function request(url, options = {}) {
  const defaultHeaders = { 'Content-Type': 'application/json' };
  const config = {
    ...options,
    headers: { ...defaultHeaders, ...options.headers }
  };
  const response = await fetch(url, config);
  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new Error(error.message || `HTTP ${response.status}`);
  }
  return response.json();
}

// Использование
request('/api/users')
  .then(users => console.log(users))
  .catch(err => console.error(err));

Что в итоге

Fetch API — это современный, удобный и мощный инструмент для асинхронных запросов к серверу. Он основан на промисах, легко читается и отлично работает с async/await. Главное — не забывать проверять статус ответа и обрабатывать ошибки. Используйте AbortController для отмены запросов, создавайте обёртки для повторяющихся действий. Тогда ваш код будет чистым и надёжным.

Практикуйтесь, экспериментируйте с разными методами и форматами. Fetch — это навык, который пригодится в любом веб-проекте.

Студия WNDER