Использование sendBeacon для отправки при закрытии вкладки

sendBeacon — это современный API для асинхронной отправки данных на сервер, который обеспечивает высокую вероятность доставки информации даже в моменты, когда страница закрывается или пользователь покидает сайт. В контексте Web Vitals он применяется для надежной передачи метрик пользовательского опыта, таких как CLS, LCP, FID, INP, без риска их потери из-за завершения сессии.

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

Метод navigator.sendBeacon(url, data) позволяет отправлять данные в фоновом режиме. Ключевые особенности:

  • Асинхронность: отправка не блокирует выполнение скриптов и не влияет на загрузку страницы.
  • Гарантированная попытка доставки: браузер старается завершить отправку даже при закрытии вкладки или навигации по ссылке.
  • Поддержка бинарных данных: можно передавать объекты Blob, FormData, ArrayBuffer или строки.
  • Независимость от ответа сервера: API не ждет ответа и не блокирует поток.

Пример базового использования

window.addEventListener('unload', () => {
    const metrics = {
        cls: 0.05,
        lcp: 1500,
        fid: 10
    };

    const blob = new Blob([JSON.stringify(metrics)], { type: 'application/json' });
    navigator.sendBeacon('/collect-metrics', blob);
});

В этом примере данные Web Vitals собираются при событии unload, преобразуются в Blob с MIME-типом application/json и отправляются на сервер с помощью sendBeacon.

Отличие от fetch и XMLHttpRequest

Характеристика sendBeacon fetch / XMLHttpRequest
Асинхронность при unload Да Нет, запрос может быть прерван
Гарантия отправки Высокая Нет, запрос может не завершиться
Воздействие на UI Минимальное Может блокировать обработку событий
Поддержка больших данных Ограничена размером Blob Зависит от сервера и браузера

sendBeacon особенно ценен для отправки данных при закрытии вкладки, где обычные fetch или XMLHttpRequest могут быть прерваны браузером.

Обработка ошибок и ограничений

Хотя sendBeacon гарантирует попытку отправки, есть несколько моментов:

  • Размер передаваемых данных не должен превышать ~64 КБ, иначе часть браузеров может отклонить запрос.
  • Сервер не обязательно должен отвечать данными; sendBeacon игнорирует ответ.
  • Событие unload не всегда подходит для сложной логики, так как страница может быть закрыта мгновенно.

Для более гибкой отправки метрик можно использовать сочетание visibilitychange и sendBeacon:

document.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'hidden') {
        const metrics = getWebVitalsMetrics();
        const blob = new Blob([JSON.stringify(metrics)], { type: 'application/json' });
        navigator.sendBeacon('/collect-metrics', blob);
    }
});

Использование visibilityState === 'hidden' увеличивает шанс отправки данных при смене вкладки или закрытии браузера.

Интеграция с библиотекой Web Vitals

Web Vitals предоставляет функции getCLS, getLCP, getFID, getINP, которые позволяют передавать результаты коллбэком. Пример с sendBeacon:

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

function sendMetric(metric) {
    const blob = new Blob([JSON.stringify(metric)], { type: 'application/json' });
    navigator.sendBeacon('/collect-metrics', blob);
}

getCLS(sendMetric);
getLCP(sendMetric);
getFID(sendMetric);

Здесь каждый вызов функции Web Vitals формирует объект метрики, который сразу отправляется на сервер, минимизируя вероятность потери данных при уходе пользователя.

Рекомендации по применению

  • Собирать только критические метрики: CLS, LCP, FID, INP.
  • Использовать visibilitychange вместе с unload для максимальной надежности.
  • Минимизировать размер передаваемых данных, чтобы не превышать ограничения браузеров.
  • Сервер должен принимать JSON без ожидания сложной обработки, так как ответ игнорируется.

Использование sendBeacon с Web Vitals позволяет построить устойчивую систему аналитики пользовательского опыта, которая работает даже в условиях резкой навигации или закрытия вкладки. Это ключевой инструмент для точной оценки производительности и UX на современном веб-сайте.