Улучшение закрытия страницы в синхронном XMLHttpRequest()

Уменьшение задержки навигации

Джо Медли
Joe Medley

Обычно страница или приложение имеют неотправленные аналитические или другие данные в тот момент, когда пользователь закрывает их. Чтобы предотвратить потерю данных, некоторые сайты используют синхронный вызов XMLHttpRequest() , чтобы страница или приложение оставались открытыми до тех пор, пока их данные не будут переданы на сервер. Мало того, что существуют лучшие способы сохранения данных, но этот метод создает плохой пользовательский опыт, задерживая закрытие страницы на несколько секунд.

Эту практику необходимо изменить, и браузеры реагируют. Спецификация XMLHttpRequest() уже устарела и удалена . Chrome 80 делает первый шаг, запрещая синхронные вызовы внутри нескольких обработчиков событий, в частности, beforeunload , unload , pagehide и visibilitychange , когда они запускаются при увольнении. WebKit также недавно получил коммит, реализующий такое же изменение поведения .

В этой статье я кратко опишу варианты для тех, кому нужно время на обновление своих сайтов, и обрисую альтернативы XMLHttpRequest() .

Временный отказ

Chrome не хочет просто отключать XMLHttpRequest() , поэтому доступно несколько вариантов временного отказа. Для сайтов в Интернете доступна пробная версия Origin . При этом вы добавляете в заголовки страниц токен, специфичный для источника, который обеспечивает синхронные вызовы XMLHttpRequest() . Действие этой опции прекращается незадолго до выхода Chrome 89, где-то в марте 2021 года. Клиенты Enterprise Chrome также могут использовать флаг политики AllowSyncXHRInPageDismissal , действие которого прекращается в то же время.

Альтернативы

Независимо от того, как вы отправляете данные обратно на сервер, лучше не дожидаться выгрузки страницы, чтобы отправить все данные одновременно. Помимо неприятного пользовательского опыта, выгрузка ненадежна в современных браузерах и рискует потерять данные, если что-то пойдет не так. В частности, события выгрузки часто не запускаются в мобильных браузерах , поскольку существует множество способов закрыть вкладку или браузер в мобильных операционных системах без запуска события unload . При использовании XMLHttpRequest() выбором было использование небольших полезных данных. Теперь это требование. Обе альтернативы имеют ограничение на загрузку в 64 КБ на контекст, как того требует спецификация.

Получить подтверждение активности

API Fetch предоставляет надежные средства взаимодействия с сервером и согласованный интерфейс для использования API различных платформ. Среди его опций — keepalive , который гарантирует, что запрос продолжится независимо от того, останется ли страница, вызвавшая его, открытой:

window.addEventListener('unload', {
  fetch('/siteAnalytics', {
    method: 'POST',
    body: getStatistics(),
    keepalive: true
  });
}

Преимущество метода fetch() заключается в большем контроле над тем, что отправляется на сервер. В этом примере я не показываю, что fetch() также возвращает обещание, которое разрешается с помощью объекта Response . Поскольку я пытаюсь избежать выгрузки страницы, я решил ничего с ней не делать.

ОтправитьМаяк()

SendBeacon() на самом деле использует Fetch API под капотом, поэтому он имеет такое же ограничение полезной нагрузки в 64 КБ и почему он также гарантирует продолжение запроса после выгрузки страницы. Его главное преимущество – простота. Он позволяет отправлять данные с помощью одной строки кода:

window.addEventListener('unload', {
  navigator.sendBeacon('/siteAnalytics', getStatistics());
}

Заключение

Надеемся, что с увеличением доступности fetch() в браузерах XMLHttpRequest() в какой-то момент будет удален с веб-платформы. Производители браузеров согласны с тем, что его следует удалить, но это займет время. Отказ от одного из худших вариантов использования — это первый шаг, который улучшит взаимодействие с пользователем для всех.

Фото Мэтью Хэмилтона на Unsplash