Fetch API и HTTP запросы

Fetch API — современный способ выполнения HTTP-запросов в браузере с использованием промисов. В отличие от устаревшего XMLHttpRequest, Fetch предоставляет более лаконичный и гибкий интерфейс для работы с сетью. Основная функция — fetch(), которая принимает URL и опциональный объект конфигурации.

fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Ошибка сети: ' + response.status);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Произошла ошибка:', error));

Ключевые моменты:

  • fetch возвращает промис, который резолвится в объект Response.
  • Проверка response.ok необходима для обработки HTTP-ошибок.
  • Для получения тела ответа используются методы json(), text(), blob(), arrayBuffer().

Конфигурация запросов

Объект конфигурации позволяет задавать метод, заголовки, тело запроса и другие параметры:

fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify({ name: 'Preact', type: 'framework' })
})
  .then(response => response.json())
  .then(data => console.log(data));

Особенности:

  • Методы: GET, POST, PUT, DELETE, PATCH.
  • Заголовки (headers) задаются объектом, где ключи — имя заголовка, значения — строки.
  • Тело запроса (body) должно быть сериализовано для форматов JSON или FormData.

Асинхронная обработка с async/await

Fetch удобно использовать с async/await, что делает код более читаемым и последовательным:

async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('Ошибка сети');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

fetchData();

Обработка ошибок и таймауты

Fetch не бросает ошибку при HTTP-кодах ошибок, поэтому проверка response.ok обязательна. Для таймаутов можно использовать AbortController:

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

setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch('https://api.example.com/data', { signal });
  const data = await response.json();
} catch (error) {
  if (error.name === 'AbortError') {
    console.error('Запрос прерван из-за таймаута');
  } else {
    console.error('Ошибка запроса:', error);
  }
}

Использование Fetch API в Preact

В Preact Fetch часто применяют для загрузки данных в компонентах. Наиболее распространённый подход — использование хука useEffect вместе с useState:

import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function loadData() {
      try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) throw new Error('Ошибка загрузки данных');
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }
    loadData();
  }, []);

  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;
  return (
    <div>
      {data.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
}

Принципы работы:

  • useEffect обеспечивает выполнение запроса после рендера компонента.
  • useState хранит состояние данных, загрузки и ошибок.
  • Асинхронная функция внутри useEffect позволяет корректно использовать await.

Оптимизация запросов

  1. Кэширование: использование localStorage или sessionStorage для повторного использования данных без лишних запросов.
  2. Параллельные запросы: Promise.all позволяет выполнять несколько fetch одновременно:
const [users, posts] = await Promise.all([
  fetch('/users').then(res => res.json()),
  fetch('/posts').then(res => res.json())
]);
  1. Дебаунс запросов: при динамическом поиске рекомендуется задерживать вызов fetch, чтобы уменьшить количество сетевых операций.

Работа с REST и GraphQL

  • Для REST Fetch используется стандартно с методами GET, POST, PUT и т.д.
  • Для GraphQL требуется POST-запрос с JSON-телом:
const query = `
  query {
    users {
      id
      name
    }
  }
`;

const response = await fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query })
});
const result = await response.json();

Заключение по практическому использованию

Fetch API обеспечивает универсальный и гибкий механизм работы с HTTP-запросами. В Preact его сочетание с хуками позволяет создавать реактивные компоненты, эффективно загружающие данные, обрабатывающие ошибки и управляемые состоянием. Асинхронная обработка, контроль таймаутов и оптимизация запросов являются ключевыми аспектами построения производительных и надежных веб-приложений.