È normale che le pagine web debbano inviare dati (o "beacon") al proprio server, ad esempio i dati di analisi per la sessione corrente di un utente. Per gli sviluppatori, questo richiede un equilibrio: ridurre le richieste costanti, eventualmente ridondanti, senza rischiare di perdere dati se la scheda è stata chiusa o l'utente ha abbandonato la pagina prima che un beacon possa essere inviato.
Tradizionalmente, gli sviluppatori utilizzano gli eventi pagehide
e visibilitychange
per acquisire la pagina durante lo scollegamento e poi navigator.sendBeacon()
o fetch()
con keepalive
per i dati del beacon. Tuttavia, entrambi questi eventi presentano casi limite difficili che variano in base al browser dell'utente e, a volte, non arrivano mai, soprattutto sui dispositivi mobili.
fetchLater()
è una proposta per sostituire questa complessità con una singola chiamata API. Funziona esattamente come suggerisce il nome: chiede al browser di assicurarsi che venga effettuata una richiesta in un secondo momento, anche se la pagina viene chiusa o l'utente esce dalla pagina.
fetchLater()
è disponibile in Chrome per i test con utenti reali nell'ambito di una prova dell'origine a partire dalla versione 121 (rilasciata a gennaio 2024) e fino al 3 settembre 2024.
L'API fetchLater()
const fetchLaterResult = fetchLater(request, options);
fetchLater()
accetta due argomenti, generalmente identici a quelli di fetch()
:
- L'elemento
request
, che può essere un URL di stringa o un'istanzaRequest
. - Un oggetto
options
facoltativo, che estendeoptions
dafetch()
con un timeout chiamatoactivateAfter
.
fetchLater()
restituisce un FetchLaterResult
, che al momento contiene una sola proprietà di sola lettura activated
, che verrà impostata su true
quando sarà trascorso il tempo "più tardi" e il recupero sarà stato eseguito. Qualsiasi risposta alla richiesta fetchLater()
viene ignorata.
request
L'utilizzo più semplice è un URL da solo:
fetchLater('/endpoint/');
Tuttavia, proprio come per fetch()
, è possibile impostare un numero elevato di opzioni in una richiesta fetchLater()
, tra cui intestazioni personalizzate, comportamento delle credenziali, un corpo POST
e un AbortController
signal
per annullarla potenzialmente.
fetchLater('/endpoint/', {
method: 'GET',
cache: 'no-store',
mode: 'same-origin',
headers: {Authorization: 'SUPER_SECRET'},
});
options
L'oggetto options estende le opzioni di fetch()
con un timeout, activateAfter
, nel caso in cui tu voglia attivare la richiesta dopo il timeout o quando la pagina viene scaricata, a seconda del caso che si verifica per primo.
In questo modo puoi decidere il compromesso tra ottenere i dati all'ultimo momento possibile o quando i dati sono più aggiornati.
Ad esempio, se hai un'app che gli utenti di solito mantengono aperta per l'intera giornata lavorativa, ti consigliamo di impostare un timeout di un'ora per garantire analisi più granulari, garantendo al contempo un beacon se l'utente è uscito prima del termine dell'ora. È quindi possibile configurare un nuovo fetchLater()
per l'ora successiva di analisi.
const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});
Esempio di utilizzo
Un problema quando misuri Core Web Vitals sul campo è che qualsiasi metrica sul rendimento potrebbe cambiare finché l'utente non abbandona effettivamente una pagina. Ad esempio, variazioni del layout più significative potrebbero verificarsi in qualsiasi momento oppure la pagina potrebbe impiegare ancora più tempo per rispondere a un'interazione.
Tuttavia, non vorrai rischiare di perdere tutti i dati sul rendimento a causa di beaconing con bug o imprecisi all'unload della pagina. È un candidato perfetto per fetchLater()
.
In questo esempio, la libreria web-vitals.js viene utilizzata per monitorare le metriche e fetchLater()
per generare report sui risultati in un endpoint di analisi:
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);
Ogni volta che viene ricevuto un aggiornamento della metrica, qualsiasi fetchLater()
pianificato esistente viene annullato con un AbortController
e viene creato un nuovo fetchLater()
con l'aggiornamento incluso.
Prova fetchLater()
Come indicato, fetchLater()
è disponibile in una prova di origine fino a Chrome 126. Per informazioni di base sulle prove delle origini, consulta "Iniziare a utilizzare le prove delle origini"
Per i test locali, fetchLater
può essere attivato con il flag delle funzionalità della piattaforma web sperimentale in chrome://flags/#enable-experimental-web-platform-features
. Può anche essere attivato eseguendo Chrome dalla riga di comando con --enable-experimental-web-platform-features
o con il flag --enable-features=FetchLaterAPI
più mirato.
Se la utilizzi in una pagina pubblica, assicurati di rilevare la funzionalità controllando se è stato definito il fetchLater
globale prima di utilizzarla:
if (globalThis.fetchLater) {
// Set up beaconing using fetchLater().
// ...
}
Feedback
Il feedback degli sviluppatori è essenziale per utilizzare correttamente le nuove API web, quindi segnala problemi e feedback su GitHub.