It's common for a page or app to have unsubmitted analytics or other data at the time a user closes it. To prevent data loss, some sites use a synchronous call to XMLHttpRequest() to keep the page or app open until its data is passed to the server. Not only are there better ways to save data, but this technique creates a bad user experience by delaying closing of the page for up to several seconds.
This practice needs to change, and browsers are responding. The XMLHttpRequest() specification is already slated for deprecation and removal . Chrome 80 takes the first step by disallowing synchronous calls inside several event handlers, specifically beforeunload , unload , pagehide , and visibilitychange when they are fired in the dismissal. WebKit also recently landed a commit implementing the same behavior change .
Я кратко опишу варианты для тех, кому нужно время для обновления своих сайтов, и изложу альтернативы функции XMLHttpRequest() .
Временные отказы от участия
Chrome хочет предоставить разработчикам время для отказа от использования функции XMLHttpRequest() , поэтому мы предложили временные варианты отказа.
Присоединяйтесь к пробной версии . Это позволит добавить в заголовки страницы токен, специфичный для конкретного источника, который разрешает синхронные вызовы XMLHttpRequest() . Эта опция будет недоступна до выхода Chrome 89, примерно в марте 2021 года. Корпоративные клиенты Chrome также могут использовать флаг политики AllowSyncXHRInPageDismissal , действие которого также прекратится.
Альтернативы
Regardless of how you send data back to the server, it's best to avoid waiting until page unload to send all the data at once. Aside from creating a bad user experience, unload is unreliable on modern browsers and risks data loss if something goes wrong. Specifically, unload events often don't fire on mobile browsers because there are many ways to close a tab or browser on mobile operating systems without the unload event firing. With XMLHttpRequest() , using small payloads was a choice. Now it's a requirement. Both of its alternatives have an upload limit of 64 KB per context, as required by the specification.
Fetch keepalive
API Fetch предоставляет надежный способ обработки взаимодействий с сервером и согласованный интерфейс для использования с API различных платформ. Среди его опций — keepalive , который гарантирует, что запрос будет продолжен независимо от того, остается ли открытой страница, отправившая его:
window.addEventListener('unload', {
fetch('/siteAnalytics', {
method: 'POST',
body: getStatistics(),
keepalive: true
});
}
Метод fetch() имеет преимущество в большем контроле над тем, что отправляется на сервер. В примере я не показываю, что fetch() также возвращает промис, который разрешается объектом Response . Поскольку я пытаюсь избежать проблем с выгрузкой страницы, я решил ничего с этим не делать.
SendBeacon()
SendBeacon() actually uses the Fetch API under the hood, which is why it has the same 64 KB payload limitation and why it also ensures that a request continues after a page unload. Its primary advantage is its simplicity. It lets you submit your data with a single line of code:
window.addEventListener('unload', {
navigator.sendBeacon('/siteAnalytics', getStatistics());
}
Заключение
Благодаря расширенной доступности функции fetch() во всех браузерах, есть надежда, что XMLHttpRequest() будет удален из веб-платформы. Производители браузеров согласны с тем, что его следует удалить, но это займет время. Отказ от одного из худших вариантов его использования — это первый шаг к улучшению пользовательского опыта для всех.