Se mejoró el descarte de páginas en XMLHttpRequest() síncrono

Cómo reducir las navegaciones retrasadas

Joe Medley
Joe Medley

Es común que una página o aplicación tenga estadísticas o datos sin enviar cuando un usuario la cierra. Para evitar la pérdida de datos, algunos sitios usan una llamada síncrona a XMLHttpRequest() para mantener la página o app abiertas hasta que se pasan sus datos al servidor. No solo hay mejores formas de guardar datos, sino que esta técnica crea una mala experiencia del usuario, ya que retrasa el cierre de la página hasta por varios segundos.

Esta práctica debe cambiar, y los navegadores responden. La especificación de XMLHttpRequest() ya está programada para su baja y eliminación. Chrome 80 da el primer paso y no permite llamadas síncronas dentro de varios controladores de eventos, específicamente beforeunload, unload, pagehide y visibilitychange cuando se activan en el rechazo. Recientemente, WebKit también incluye una confirmación que implementa el mismo cambio de comportamiento.

En este artículo, describiré brevemente las opciones para quienes necesiten tiempo para actualizar sus sitios y describiré las alternativas a XMLHttpRequest().

Inhabilitaciones temporales

Chrome no quiere dejar de usar XMLHttpRequest(), por lo que hay algunas opciones temporales para inhabilitar esta función. Para los sitios de Internet, hay una prueba de origen disponible. Con esto, agregas un token específico del origen a los encabezados de tu página que habilita las llamadas XMLHttpRequest() síncronas. Esta opción finaliza poco antes del envío de Chrome 89, en marzo de 2021. Los clientes de Chrome Enterprise también pueden usar la marca de política AllowSyncXHRInPageDismissal, que finaliza al mismo tiempo.

Alternativas

Independientemente de cómo envíes los datos al servidor, es mejor evitar esperar hasta que se descargue la página para enviar todos los datos a la vez. Además de crear una mala experiencia del usuario, la descarga no es confiable en los navegadores modernos y corre el riesgo de perder datos si se produce un error. Específicamente, los eventos de descarga a menudo no se activan en navegadores para dispositivos móviles, ya que hay muchas formas de cerrar una pestaña o un navegador en sistemas operativos para dispositivos móviles sin que se active el evento unload. Con XMLHttpRequest(), usar cargas útiles pequeñas era una opción. Ahora es un requisito. Ambas alternativas tienen un límite de carga de 64 KB por contexto, según lo requiera la especificación.

Cómo recuperar el estado de keepalive

La API de Fetch proporciona una forma sólida de procesar las interacciones del servidor y una interfaz coherente para usar en diferentes APIs de la plataforma. Entre sus opciones, se encuentra keepalive, que garantiza que una solicitud continúe, independientemente de si la página que la realizó permanece abierta o no:

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

El método fetch() tiene la ventaja de tener un mayor control sobre lo que se envía al servidor. Lo que no muestro en el ejemplo es que fetch() también muestra una promesa que se resuelve con un objeto Response. Como estoy tratando de evitar la descarga de la página, decidí no hacer nada con ella.

SendBeacon()

En realidad, SendBeacon() usa la API de Fetch, por lo que tiene la misma limitación de carga útil de 64 KB y también garantiza que una solicitud continúe después de que se descargue una página. Su principal ventaja es su simplicidad. Te permite enviar tus datos con una sola línea de código:

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

Conclusión

Con el aumento de la disponibilidad de fetch() en los navegadores, se espera que XMLHttpRequest() se quite de la plataforma web en algún momento. Los proveedores de navegadores coinciden en que se debe quitar, pero esto llevará tiempo. Dar de baja uno de sus peores casos de uso es un primer paso que mejora la experiencia del usuario para todos.

Foto de Matthew Hamilton en Unsplash