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

Cómo reducir las navegaciones retrasadas

Joe Medley
José Medley

Es común que una página o app tenga estadísticas o datos que no se enviaron cuando el usuario las 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 pasen los datos al servidor. No solo existen 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 durante varios segundos.

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

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

Inhabilitaciones temporales

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

Alternativas

Sin importar cómo envíes los datos al servidor, es mejor evitar esperar hasta la descarga de 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 que se pierdan datos si se produce algún error. Específicamente, los eventos de descarga a menudo no se activan en los navegadores para dispositivos móviles porque existen muchas maneras de cerrar una pestaña o un navegador en los sistemas operativos para dispositivos móviles sin que se active el evento unload. Con XMLHttpRequest(), el uso de cargas útiles pequeñas era una decisión. Ahora es un requisito. Ambas alternativas tienen un límite de carga de 64 KB por contexto, como lo requiere la especificación.

Cómo recuperar keepalive

La API de Fetch proporciona un medio sólido para manejar las interacciones del servidor y una interfaz coherente que se usa en diferentes APIs de la plataforma. Una de sus opciones es keepalive, que garantiza que una solicitud continúe sin importar si la página que la hizo permanezca 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. En el ejemplo, no se muestra que fetch() también muestra una promesa que se resuelve con un objeto Response. Como trato de no interrumpir la descarga de la página, elegí no hacer nada al respecto.

SendBeacon()

SendBeacon() en realidad usa la API de Fetch de forma interna, por lo que tiene la misma limitación de carga útil de 64 KB y por qué también garantiza que la 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 la mayor disponibilidad de fetch() en todos los navegadores, se espera que XMLHttpRequest() se quite de la plataforma web en algún momento. Los proveedores de navegadores aceptan que se debe quitar, pero tomará 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