Использование fetch с keepalive

fetch с опцией keepalive является важным инструментом для отправки запросов на сервер в случаях, когда нужно гарантировать их выполнение даже при закрытии страницы или переходе на другой URL. Это особенно актуально для аналитики, логирования событий и передачи данных о взаимодействиях пользователя, когда терять запросы недопустимо.

Основы keepalive

Свойство keepalive — это булевый флаг, который можно передать в объект настроек запроса fetch:

fetch('/api/log', {
  method: 'POST',
  body: JSON.stringify({event: 'click'}),
  headers: {
    'Content-Type': 'application/json'
  },
  keepalive: true
});

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

  • keepalive: true позволяет браузеру завершить отправку запроса даже после того, как страница начала закрываться.
  • Ограничения по размеру: большинство браузеров ограничивают тело запроса до ~64KB при использовании keepalive.
  • Метод запроса должен быть безопасным для такого использования. Обычно применяют POST для передачи данных, но GET-запросы также поддерживаются.

Отличие от обычного fetch

При обычном использовании fetch браузер отменяет все незавершённые запросы, если пользователь закрывает вкладку или переходит на другой URL. Включение keepalive предотвращает эту проблему.

Пример без keepalive:

window.addEventListener('unload', () => {
  fetch('/api/log', {
    method: 'POST',
    body: JSON.stringify({event: 'page-unload'}),
    headers: {
      'Content-Type': 'application/json'
    }
  });
});

В этом случае браузер почти наверняка не успеет отправить запрос до закрытия страницы. С keepalive:

window.addEventListener('unload', () => {
  fetch('/api/log', {
    method: 'POST',
    body: JSON.stringify({event: 'page-unload'}),
    headers: {
      'Content-Type': 'application/json'
    },
    keepalive: true
  });
});

Теперь данные будут переданы надёжно, даже если страница уже закрывается.

Ограничения и нюансы

  1. Размер данных keepalive не предназначен для отправки больших payload’ов. Если нужно отправить больше 64KB, лучше использовать обычный fetch при активной странице или очереди отправки данных на сервер через Web Worker.

  2. Синхронные альтернативы До появления keepalive использовался navigator.sendBeacon(). Этот метод также гарантирует отправку данных при закрытии страницы, но ограничен POST-запросами и некоторыми заголовками. fetch с keepalive расширяет функциональность и позволяет использовать дополнительные возможности HTTP, например, кастомные заголовки.

  3. Совместимость браузеров Поддержка keepalive есть в современных версиях Chrome, Firefox, Edge и Safari. В старых браузерах данный флаг игнорируется, и поведение запроса совпадает с обычным fetch.

Применение с Web Vitals

keepalive особенно полезен при сборе метрик Web Vitals (LCP, FID, CLS), поскольку данные нужно отправлять в аналитическую систему даже в момент закрытия страницы:

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToAnalytics(metric) {
  fetch('/analytics', {
    method: 'POST',
    body: JSON.stringify(metric),
    headers: {'Content-Type': 'application/json'},
    keepalive: true
  });
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

Особенности интеграции:

  • Все метрики отправляются независимо от того, активно ли окно браузера.
  • Использование keepalive предотвращает потерю данных при резком закрытии вкладки.
  • Можно комбинировать с requestAnimationFrame или setTimeout для оптимизации отправки данных, чтобы не блокировать UI.

Практические рекомендации

  • Не использовать keepalive для больших файлов или медленных запросов.
  • Отправлять только критические данные, которые не могут быть потеряны.
  • Для массовых или объёмных запросов использовать фоновые сервисы (Service Worker) или очередь запросов.
  • Всегда указывать заголовок Content-Type при передаче JSON, чтобы сервер корректно обрабатывал данные.

fetch с keepalive является мощным инструментом для надёжной передачи данных на сервер в ситуациях, когда стандартный fetch может быть прерван. Его грамотное использование позволяет интегрировать сбор аналитики и метрик без потери данных, даже в сценариях закрытия страницы или навигации.