> Как отправить состояние при закрытии страницы браузера? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: elirox

Стек: JavaScript

> Пример ответа

Короткий ответ

Для отправки состояния при закрытии страницы используйте navigator.sendBeacon() - он гарантирует отправку даже при закрытии вкладки. Альтернатива - синхронный XMLHttpRequest в обработчике beforeunload, но он может быть заблокирован браузером. fetch с keepalive: true также работает, но sendBeacon предпочтительнее, так как не блокирует основной поток и гарантирует доставку.

Подробное объяснение

При закрытии страницы браузер завершает выполнение JavaScript, и асинхронные запросы (обычный fetch, XMLHttpRequest) могут быть отменены. Основные события для отслеживания закрытия: beforeunload (срабатывает перед выгрузкой, позволяет отменить закрытие) и unload (срабатывает при выгрузке, но менее надёжен). visibilitychange с document.visibilityState === 'hidden' также подходит, так как срабатывает при переходе на другую вкладку или закрытии.

navigator.sendBeacon() отправляет небольшой объём данных (обычно до 64 КБ) асинхронно, но с гарантией доставки - браузер выполняет запрос даже после завершения страницы. Он использует POST-запрос и не ждёт ответа. Это стандартный механизм для аналитики и логов.

fetch с опцией keepalive: true работает аналогично, но может быть менее эффективным для больших объёмов данных. Синхронный XMLHttpRequest в beforeunload - устаревший подход, который браузеры могут блокировать или показывать предупреждения.

На практике

Наиболее надёжный способ - использовать navigator.sendBeacon() в обработчике beforeunload или visibilitychange. Для критически важных данных (например, сохранение черновика) комбинируйте с периодическим сохранением. Учитывайте, что sendBeacon не поддерживает кастомные заголовки - для них используйте fetch с keepalive. Также проверяйте, что данные не превышают лимит (обычно 64 КБ).

Пример кода

JAVASCRIPT
// Отправка состояния при закрытии страницы
window.addEventListener('beforeunload', () => {
const state = {
lastSaved: Date.now(),
userId: 123,
data: 'some important state'
};
// Используем sendBeacon для гарантированной отправки
const blob = new Blob([JSON.stringify(state)], { type: 'application/json' });
navigator.sendBeacon('/api/save-state', blob);
});
// Альтернатива с fetch + keepalive
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
fetch('/api/logout', {
method: 'POST',
keepalive: true,
body: JSON.stringify({ sessionId: 'abc' }),
headers: { 'Content-Type': 'application/json' }
});
}
});

Как отвечать на собеседовании

Начните с ключевого решения - navigator.sendBeacon(). Объясните, почему асинхронные запросы не работают при закрытии страницы. Упомяните альтернативы (fetch с keepalive, синхронный XHR) и их ограничения. Подчеркните, что sendBeacon - стандарт для аналитики и логов. Если спросят про объём данных, скажите про лимит 64 КБ. Для больших данных предложите сохранять частями или использовать Service Worker.

Что проверяет интервьюер

  • Понимание жизненного цикла страницы и событий выгрузки.
  • Знание механизмов гарантированной отправки данных.
  • Умение выбирать правильный API под задачу.
  • Осведомлённость об ограничениях (размер данных, поддержка заголовков).
  • Практический опыт работы с аналитикой и сохранением состояния.

Типичные ошибки

  • Использование асинхронного fetch без keepalive - запрос не выполнится.
  • Полагаться только на unload - событие может не сработать в мобильных браузерах.
  • Отправка слишком больших данных через sendBeacon - запрос будет отклонён.
  • Использование beforeunload для обязательной отправки - пользователь может отменить закрытие.
  • Забыть про visibilitychange для случаев, когда вкладка не закрывается, а скрывается.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью