La prova dell'origine API fetchLater

Brendan Kenny
Brendan Kenny

È normale che le pagine web debbano inviare dei dati (o "beacon") al proprio server; ad esempio, pensa ai dati di analisi relativi alla sessione corrente di un utente. Per gli sviluppatori, questo richiede un esercizio di bilanciamento: ridurre le richieste costanti, potenzialmente ridondanti senza rischiare di perdere dati se la scheda è stata chiusa o se l'utente è uscito dalla pagina prima di poter inviare un beacon.

Tradizionalmente, gli sviluppatori utilizzano gli eventi pagehide e visibilitychange per rilevare la pagina durante l'unload, quindi utilizzano navigator.sendBeacon() o fetch() con keepalive per beaconing dei dati. Tuttavia, entrambi questi eventi presentano situazioni particolari che variano in base al browser dell'utente e, a volte, non arrivano mai del tutto, specialmente sui dispositivi mobili.

fetchLater() è una proposta per sostituire questa complessità con una singola chiamata API. Fa esattamente come suggerisce il nome: chiede al browser di assicurarsi che venga effettuata una richiesta in futuro, anche se la pagina viene chiusa o l'utente esce dalla pagina.

fetchLater() è disponibile in Chrome per i test con utenti reali sottoposti a una prova dell'origine a partire dalla versione 121 (rilasciata a gennaio 2024) e fino a Chrome 126 (luglio 2024).

L'API fetchLater()

const fetchLaterResult = fetchLater(request, options);

fetchLater() accetta due argomenti, generalmente identici a quelli di fetch():

  • request, che può essere un URL stringa o un'istanza Request.
  • Un oggetto options facoltativo, che estende options da fetch() con un timeout chiamato activateAfter.

fetchLater() restituisce FetchLaterResult, che contiene attualmente una sola proprietà di sola lettura activated, che verrà impostata su true una volta trascorso il periodo "più tardi" ed eseguito il recupero. Qualsiasi risposta alla richiesta fetchLater() viene ignorata.

request

L'utilizzo più semplice è costituito da un URL:

fetchLater('/endpoint/');

Tuttavia, proprio come fetch(), è possibile impostare un numero elevato di opzioni su una richiesta fetchLater(), tra cui intestazioni personalizzate, comportamento delle credenziali, un corpo POST e un AbortController signal per potenzialmente annullarla.

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 dell'evento che si verifica per primo.

In questo modo puoi decidere il compromesso tra la ricezione dei dati all'ultimo momento possibile o quando è più tempestivo.

Ad esempio, se hai un'app che solitamente i tuoi utenti tengono aperta per l'intera giornata lavorativa, potresti avere bisogno di un timeout di un'ora per garantire analisi più granulari, garantendo al contempo un beacon se l'utente usciva in qualsiasi momento prima dello scadere di quell'ora. Puoi quindi configurare un nuovo fetchLater() per la prossima ora di analisi.

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

Esempio di utilizzo

Un problema che si verifica quando si misurano i Segnali web essenziali sul campo è che qualsiasi metrica sulle prestazioni potrebbe cambiare finché l'utente non esce effettivamente dalla pagina. Ad esempio, potrebbero verificarsi variazioni del layout più ampie in qualsiasi momento o la pagina potrebbe impiegare ancora più tempo per rispondere a un'interazione.

Tuttavia, non vuoi rischiare di perdere tutti i dati sulle prestazioni a causa di bug o beaconing incompleti durante l'unload della pagina. È un candidato perfetto per fetchLater().

In questo esempio, la libreria web-vitals.js viene utilizzata per monitorare le metriche e fetchLater() viene utilizzato per segnalare i risultati a 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 eseguito un aggiornamento delle metriche, qualsiasi fetchLater() pianificata esistente viene annullata con un AbortController e viene creato un nuovo fetchLater() con l'aggiornamento incluso.

Prova fetchLater()

Come indicato, fetchLater() è disponibile in una prova dell'origine fino a Chrome 126. Per informazioni di base sulle prove dell'origine, consulta la sezione "Iniziare a utilizzare le prove dell'origine".

Per i test locali, è possibile attivare fetchLater con il flag delle funzionalità della piattaforma web sperimentale all'indirizzo chrome://flags/#enable-experimental-web-platform-features. Per attivarlo, puoi anche eseguire Chrome dalla riga di comando con --enable-experimental-web-platform-features o con il flag --enable-features=FetchLaterAPI più mirato.

Se lo usi in una pagina pubblica, assicurati di rilevare la funzionalità controllando se è stato definito l'elemento fetchLater globale prima di utilizzarlo:

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

Feedback

Il feedback degli sviluppatori è essenziale per ottenere correttamente nuove API web, quindi invia problemi e feedback su GitHub.

Maggiori informazioni