La prueba de origen de la API de fetchLater

Brendan Kenny
Brendan Kenny

Es común que las páginas web necesiten enviar datos (o “contador”) de vuelta a su servidor; por ejemplo, piensen en los datos de análisis de la sesión actual de un usuario. Para los desarrolladores, esto requiere un equilibrio: reducir las solicitudes constantes, posiblemente redundantes, sin arriesgarse a perder datos si la pestaña se cerró o el usuario navegó antes de que se pudiera enviar una baliza.

Tradicionalmente, los desarrolladores usaban eventos pagehide y visibilitychange para detectar la página mientras se descarga y, luego, usaban navigator.sendBeacon() o fetch() con keepalive para el pixel contador de datos. Sin embargo, ambos eventos tienen casos límite difíciles que difieren según el navegador del usuario y, a veces, los eventos nunca llegan, especialmente en los dispositivos móviles.

fetchLater() es una propuesta para reemplazar esta complejidad con una sola llamada a la API. Hace exactamente lo que su nombre sugiere: le pide al navegador que se asegure de realizar una solicitud en algún momento en el futuro, incluso si la página está cerrada o el usuario navega a otro sitio.

fetchLater() está disponible en Chrome para realizar pruebas con usuarios reales tras una prueba de origen a partir de la versión 121 (lanzada en enero de 2024) y hasta la versión 126 de Chrome (julio de 2024).

La API de fetchLater()

const fetchLaterResult = fetchLater(request, options);

fetchLater() toma dos argumentos que, por lo general, son idénticos a los de fetch():

  • El request, ya sea una URL de cadena o una instancia de Request.
  • Un objeto options opcional, que extiende el options de fetch() con un tiempo de espera llamado activateAfter

fetchLater() muestra una FetchLaterResult, que actualmente contiene una sola propiedad de solo lectura activated, que se establecerá en true cuando pase "más tarde" y se realice la recuperación. Se descarta cualquier respuesta a la solicitud fetchLater().

request

El uso más sencillo es una URL por sí sola:

fetchLater('/endpoint/');

Sin embargo, al igual que fetch(), se puede configurar una gran cantidad de opciones en una solicitud fetchLater(), incluidos los encabezados personalizados, el comportamiento de las credenciales, un cuerpo de POST y un AbortController signal para potencialmente cancelarlo.

fetchLater('/endpoint/', {
  method: 'GET',
  cache: 'no-store',
  mode: 'same-origin',
  headers: {Authorization: 'SUPER_SECRET'},
});

options

El objeto de opciones extiende las opciones de fetch() con un tiempo de espera, activateAfter, en caso de que quieras activar la solicitud después del tiempo de espera o cuando se descargue la página, lo que ocurra primero.

Esto te permite decidir el equilibrio entre obtener datos en el último momento posible o cuando sea más oportuno.

Por ejemplo, si tienes una aplicación que tus usuarios suelen mantener abierta durante todo el día laboral, es posible que desees tener un tiempo de espera de una hora para garantizar estadísticas más detalladas y, al mismo tiempo, garantizar una baliza si el usuario salió en cualquier momento antes de que esa hora haya llegado. Se puede configurar un nuevo fetchLater() para la próxima hora de estadísticas.

const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});

Ejemplo de uso

Un problema cuando se miden las Métricas web esenciales en el campo es que cualquiera de las métricas de rendimiento podría cambiar hasta que el usuario abandone la página. Por ejemplo, los cambios de diseño más grandes pueden ocurrir en cualquier momento o la página podría tardar aún más en responder a una interacción.

Sin embargo, no es recomendable arriesgarse a perder todos los datos de rendimiento debido a un pixel contador incompleto o con errores en la descarga de la página. Es la candidata perfecta para fetchLater().

En este ejemplo, se usa la biblioteca web-vitals.js para supervisar las métricas y fetchLater() para informar los resultados a un extremo de estadísticas:

import {onCLS, onINP, onLCP} from 'web-vitals';

const queue = new Set();
let fetchLaterController;
let fetchLaterResult;

function updateQueue(metricUpdate) {
  // If there was an already complete request for whatever
  // reason, clear out the queue of already-sent updates.
  if (fetchLaterResult?.activated) {
    queue.clear();
  }

  queue.add(metricUpdate);

  // JSON.stringify used here for simplicity and will likely include
  // more data than you need. Replace with a preferred serialization.
  const body = JSON.stringify([...queue]);

  // Abort any existing `fetchLater()` and schedule a new one with
  // the update included.
  fetchLaterController?.abort();
  fetchLaterController = new AbortController();
  fetchLaterResult = fetchLater('/analytics', {
    method: 'POST',
    body,
    signal: fetchLaterController.signal,
    activateAfter: 60 * 60 * 1000, // Timeout to ensure timeliness.
  });
}

onCLS(updateQueue);
onINP(updateQueue);
onLCP(updateQueue);

Cada vez que se recibe una actualización de métrica, se cancela cualquier fetchLater() programada existente con un AbortController y se crea una fetchLater() nueva con la actualización incluida.

Prueba fetchLater()

Como se indicó, fetchLater() estará disponible en una prueba de origen hasta Chrome 126. Consulte "Cómo comenzar a usar las pruebas de origen" para obtener información general sobre las pruebas de origen

Para las pruebas locales, se puede habilitar fetchLater con la marca de funciones de la plataforma web experimental en chrome://flags/#enable-experimental-web-platform-features. También se puede habilitar ejecutando Chrome desde la línea de comandos con --enable-experimental-web-platform-features o la marca --enable-features=FetchLaterAPI más segmentada.

Si la usas en una página pública, asegúrate de detectar la función. Para ello, verifica si se definió el fetchLater global antes de usarlo:

if (globalThis.fetchLater) {
  // Set up beaconing using fetchLater().
  // ...
}

Comentarios

Los comentarios de los desarrolladores son fundamentales para implementar correctamente las nuevas APIs web, así que envía tus comentarios y problemas en GitHub.

Más información