Esperienze di navigazione istantanee

Integrazione delle tecniche di precaricamento tradizionali con i service worker.

Demián Renzulli
Demián Renzulli
Gilberto Cocchi
Gilberto Cocchi

L'esecuzione di un'attività su un sito di solito prevede diversi passaggi. Ad esempio, l'acquisto di un prodotto in un sito web di e-commerce può comportare la ricerca di un prodotto, la scelta di un articolo dall'elenco dei risultati, l'aggiunta dell'articolo al carrello e il completamento dell'operazione tramite pagamento.

In termini tecnici, spostarsi tra pagine diverse significa effettuare una richiesta di navigazione. Come regola generale, non devi utilizzare intestazioni Cache-Control di lunga durata per memorizzare in cache la risposta HTML per una richiesta di navigazione. Normalmente dovrebbero essere soddisfatti tramite la rete, con Cache-Control: no-cache, per garantire che il codice HTML, insieme alla catena di richieste di rete successive, sia (ragionevolmente) aggiornato. Purtroppo, dover affrontare la rete ogni volta che l'utente apre una nuova pagina, significa purtroppo che ogni navigazione potrebbe essere lenta, perlomeno significa che non sarà affidabile veloce.

Per velocizzare queste richieste, se puoi anticipare l'azione dell'utente, puoi richiedere queste pagine e questi asset in anticipo e mantenerli nella cache per un breve periodo di tempo finché l'utente non fa clic su questi link. Questa tecnica è chiamata prefetching e viene comunemente implementata aggiungendo tag <link rel="prefetch"> alle pagine, indicando la risorsa da prelevare.

In questa guida esploreremo i diversi modi in cui i service worker possono essere utilizzati come complemento delle tecniche di prefetching tradizionali.

Casi di produzione

MercadoLibre è il più grande sito di e-commerce in America Latina. Per velocizzare le navigazioni, iniettano dinamicamente i tag <link rel="prefetch"> in alcune parti del flusso. Ad esempio, nelle pagine delle schede recuperano la pagina di risultati successiva non appena l'utente scorre fino in fondo alla scheda:

Screenshot delle pagine della scheda 1 e 2 di MercadoLibre e un tag Link Prefetch che collega entrambe.

I file prerecuperati vengono richiesti con priorità "Più bassa" e memorizzati nella cache HTTP o nella cache della memoria (a seconda che la risorsa sia memorizzabile nella cache o meno), per un periodo di tempo che varia in base ai browser. Ad esempio, a partire da Chrome 85, questo valore è 5 minuti. Le risorse vengono conservate per cinque minuti, dopodiché vengono applicate le normali regole Cache-Control per la risorsa.

L'utilizzo della memorizzazione nella cache del servizio worker può aiutarti a estendere la durata delle risorse di precaricamento oltre il periodo di cinque minuti.

Ad esempio, il portale sportivo italiano Virgilio Sport utilizza i service worker per eseguire il pre-caricamento dei post più popolari nella home page. Utilizzano inoltre l'API Network Information per evitare il pre-caricamento per gli utenti con una connessione 2G.

Logo Virgilio Sport.

Come risultato, nell'arco di tre settimane di osservazione Virgilio Sport ha osservato un miglioramento del 78% nei tempi di caricamento degli articoli e un aumento del numero di impressioni degli articoli del 45%.

Uno screenshot delle pagine della home page e degli articoli di Virgilio Sport, con le metriche sull&#39;impatto dopo il pre-caricamento.

Implementare il precaching con Workbox

Nella sezione seguente utilizzeremo Workbox per mostrare come implementare diverse tecniche di memorizzazione nella cache nel servizio worker che possono essere utilizzate come complemento di <link rel="prefetch"> o addirittura come sostituti, delegando completamente questa attività al servizio worker.

1. Prememorizza le pagine statiche e le risorse secondarie delle pagine

La precache è la capacità del service worker di salvare i file nella cache durante l'installazione.

Nei seguenti casi, la pre-memorizzazione nella cache viene utilizzata per raggiungere un obiettivo simile al precaricamento: rendere le navigazioni più veloci.

Precaricamento di pagine statiche

Per le pagine generate in fase di compilazione (ad es. about.html, contact.html) o in siti completamente statici, è sufficiente aggiungere i documenti del sito all'elenco di precache, in modo che siano già disponibili nella cache ogni volta che l'utente vi accede:

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

Precaricamento delle risorse secondarie della pagina

La pre-memorizzazione nella cache degli asset statici che le diverse sezioni del sito potrebbero utilizzare (ad es. JavaScript, CSS e così via) è una best practice generale e può migliorare ulteriormente gli scenari di precaricamento.

Per velocizzare la navigazione in un sito di e-commerce, puoi utilizzare i tag <link rel="prefetch"> nelle pagine delle schede per prelevare le pagine dei dettagli dei prodotti per i primi prodotti di una pagina della scheda. Se hai già eseguito la precache delle risorse secondarie della pagina del prodotto, la navigazione può essere ancora più veloce.

Per implementare questa funzionalità:

  • Aggiungi un tag <link rel="prefetch"> alla pagina:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Aggiungi le risorse secondarie della pagina all'elenco di precache nel service worker:
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. Estendere la durata delle risorse di prefetch

Come accennato in precedenza, <link rel="prefetch"> recupera e mantiene le risorse nella cache HTTP per un periodo di tempo limitato, dopodiché vengono applicate le regole Cache-Control per una risorsa. A partire da Chrome 85, questo valore è 5 minuti.

I worker di servizio ti consentono di estendere la durata delle pagine di prefetch, offrendo al contempo il vantaggio aggiuntivo di rendere queste risorse disponibili per l'utilizzo offline.

Nell'esempio precedente, è possibile integrare <link rel="prefetch"> utilizzato per eseguire il pre-caricamento di una pagina di prodotto con una strategia di memorizzazione nella cache del runtime di Workbox.

Per implementare questa funzionalità:

  • Aggiungi un tag <link rel="prefetch"> alla pagina:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Implementa una strategia di memorizzazione nella cache in fase di esecuzione nel service worker per questi tipi di richieste:
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

In questo caso, abbiamo scelto di utilizzare una strategia di aggiornamento dei dati non validi. In questa strategia, le pagine possono essere richieste sia dalla cache sia dalla rete, in parallelo. La risposta proviene dalla cache, se disponibile, altrimenti dalla rete. La cache viene sempre aggiornata con la risposta della rete a ogni richiesta andata a buon fine.

3. Delegare il pre-caricamento al service worker

Nella maggior parte dei casi, l'approccio migliore è utilizzare <link rel="prefetch">. Il tag è un suggerimento delle risorse progettato per rendere il precaricamento il più efficiente possibile.

In alcuni casi, però, potrebbe essere meglio delegare completamente questa attività al service worker. Ad esempio, per eseguire il pre-caricamento dei primi prodotti in una pagina di scheda di prodotto visualizzata lato client, potrebbe essere necessario inserire dinamicamente nella pagina diversi tag <link rel="prefetch"> in base a una risposta dell'API. Ciò può richiedere temporaneamente tempo sul thread principale della pagina e rendere più difficile l'implementazione.

In casi come questo, utilizza una "strategia di comunicazione da pagina al service worker" per delegare completamente l'attività di precaricamento al service worker. Questo tipo di comunicazione può essere ottenuto utilizzando worker.postMessage():

Un&#39;icona di una pagina che effettua una comunicazione bidirezionale con un worker di servizio.

Il pacchetto Workbox Window semplifica questo tipo di comunicazione, astraendo molti dettagli della chiamata sottostante in esecuzione.

Il precaricamento con la finestra Workbox può essere implementato nel seguente modo:

  • Nella pagina: chiama il service worker passandogli il tipo di messaggio e l'elenco di URL da prelevare:
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: []});
  • Nel service worker: implementa un gestore di messaggi per inviare una richiesta fetch() per il precaricamento di ogni URL:
addEventListener('message', (event) => {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});