Mejora el rechazo de la página en XMLHttpRequest síncrono

Joe Medley
Joe Medley

Es común que una página o una app tenga datos de estadísticas o de otro tipo que no se hayan enviado cuando un usuario la cierra. Para evitar la pérdida de datos, algunos sitios usan una llamada síncrona a XMLHttpRequest() para mantener abierta la página o la app hasta que sus datos se pasen 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 están respondiendo. Ya se programó la baja y la eliminación de la XMLHttpRequest() especificaciónpara su baja y. Chrome 80 da el primer paso al no permitir 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 publicó recientemente una confirmación que implementa el mismo cambio de comportamiento.

Describiré brevemente las opciones para quienes necesiten tiempo para actualizar sus sitios y describiré las alternativas a XMLHttpRequest().

Inhabilitaciones temporales

Chrome quiere ofrecer tiempo de desarrollo para quitar la dependencia de XMLHttpRequest(), por lo que ofrecemos opciones de inhabilitación temporales.

Únete a una prueba de origen. Con esto, agregas un token específico del origen a los encabezados de tu página que habilita las llamadas síncronas XMLHttpRequest(). Esta opción finaliza poco antes del lanzamiento de Chrome 89, en algún momento de 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 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 algo sale mal. En particular, los eventos de descarga a menudo no se activan en los navegadores para dispositivos móviles porque 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 requiere la especificación.

Fetch keepalive

La API de Fetch proporciona un medio sólido para abordar las interacciones del servidor y una interfaz coherente para usar en diferentes APIs de plataformas. Entre sus opciones, se encuentra keepalive, que garantiza que una solicitud continúe, ya sea que la página que la realizó permanezca abierta o no:

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

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

SendBeacon()

SendBeacon() usa la API de Fetch en segundo plano, 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 la descarga de 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 los navegadores, XMLHttpRequest() esperamos que se quite de la plataforma web. Los proveedores de navegadores están de acuerdo en que se debe quitar, pero llevará tiempo. Dar de baja uno de sus peores casos de uso es un primer paso que mejora la experiencia del usuario para todos.