Es común que las páginas web deban enviar datos (o "píxeles contadores") a su servidor. Por ejemplo, piensa en los datos de estadísticas de la sesión actual de un usuario. Para los desarrolladores, esto requiere un equilibrio: reducir las solicitudes constantes, posiblemente redundantes, sin correr el riesgo de perder datos si se cerró la pestaña o si el usuario salió de la página antes de que se pueda enviar un píxel contador.
Tradicionalmente, los desarrolladores han usado los eventos pagehide
y visibilitychange
para detectar la página a medida que se descarga y, luego, usar navigator.sendBeacon()
o un fetch()
con keepalive
para enviar datos de píxeles contadores. Sin embargo, ambos eventos tienen casos extremos difíciles que difieren según el navegador del usuario y, a veces, los eventos nunca llegan, especialmente en 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 que se realice una solicitud en algún momento en el futuro, incluso si se cierra la página o el usuario sale de ella.
fetchLater()
está disponible en Chrome para realizar pruebas con usuarios reales mediante una prueba de origen a partir de la versión 121 (lanzada en enero de 2024) y hasta el 3 de septiembre de 2024.
La API de fetchLater()
const fetchLaterResult = fetchLater(request, options);
fetchLater()
toma dos argumentos, generalmente idénticos a los de fetch()
:
- Es el
request
, ya sea una URL de cadena o una instancia deRequest
. - Es un objeto
options
opcional, que extiende eloptions
defetch()
con un tiempo de espera llamadoactivateAfter
.
fetchLater()
muestra un FetchLaterResult
, que actualmente contiene solo una propiedad de solo lectura activated
, que se establecerá en true
cuando haya pasado "más tarde" y se haya realizado 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 con fetch()
, se puede configurar una gran cantidad de opciones en una solicitud fetchLater()
, incluidos encabezados personalizados, comportamiento de credenciales, un cuerpo POST
y un AbortController
signal
para 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 si quieres obtener datos en el último momento posible o cuando sea más oportuno.
Por ejemplo, si tienes una app que los usuarios suelen mantener abierta durante toda la jornada laboral, te recomendamos que establezcas un tiempo de espera de una hora para garantizar estadísticas más detalladas y, al mismo tiempo, garantizar un píxel contador si el usuario salió en cualquier momento antes de que se agote esa hora. Luego, se puede configurar un nuevo fetchLater()
para la siguiente hora de estadísticas.
const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});
Ejemplo de uso
Un problema que se presenta 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 salga de una 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 quieres correr el riesgo de perder todos los datos de rendimiento debido a píxeles contadores con errores o incompletos cuando se descarga la página. Es un candidato perfecto para fetchLater()
.
En este ejemplo, se usa la biblioteca web-vitals.js para supervisar las métricas, y fetchLater()
se usa para informar los resultados a un extremo de Analytics:
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 llega una actualización de métrica, se cancela cualquier fetchLater()
programado existente con un AbortController
y se crea un fetchLater()
nuevo con la actualización incluida.
Prueba fetchLater()
Como se indicó, fetchLater()
está disponible en una prueba de origen hasta Chrome 126. Consulta "Comienza a usar las pruebas de origen" para obtener información general sobre las pruebas de origen.
Para las pruebas locales, fetchLater
se puede habilitar con la marca de funciones experimentales de la plataforma web 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 lo usas en una página pública, asegúrate de detectar funciones. Para ello, verifica si el fetchLater
global está definido antes de usarlo:
if (globalThis.fetchLater) {
// Set up beaconing using fetchLater().
// ...
}
Comentarios
Los comentarios de los desarrolladores son esenciales para que las nuevas APIs web funcionen correctamente, así que informa los problemas y los comentarios en GitHub.