Integrazione delle tecniche di precaricamento tradizionali con i service worker.
L'esecuzione di un'attività su un sito richiede in genere 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 vuoi utilizzare intestazioni Cache-Control
di lunga durata per memorizzare nella cache la risposta HTML per una richiesta di navigazione. Normalmente devono essere soddisfatti tramite la rete, con Cache-Control: no-cache
, per garantire che l'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 riesci a prevedere l'azione dell'utente, puoi richiedere in anticipo le pagine e gli asset e conservarli nella cache per un breve periodo di tempo finché l'utente non fa clic su questi link. Questa tecnica è chiamata prefetching e viene implementata di solito aggiungendo tag <link rel="prefetch">
alle pagine, per indicare la risorsa da precaricare.
In questa guida esploreremo diversi modi in cui i lavoratori dei servizi possono essere utilizzati come complemento delle tecniche tradizionali di precaricamento.
Casi di produzione
MercadoLibre è il più grande sito di e-commerce dell'America Latina. Per velocizzare le navigazioni, inseriscono dinamicamente i tag <link rel="prefetch">
in alcune parti del flusso. Ad esempio, nelle pagine delle schede, la pagina dei risultati successiva viene recuperata non appena l'utente scorre la scheda fino in fondo:
I file precaricati vengono richiesti al livello "Più basso" e archiviata nella cache HTTP o nella cache in memoria (a seconda che la risorsa sia memorizzabile o meno nella cache), per un periodo di tempo che varia a seconda del browser. Ad esempio, a partire da Chrome 85, questo valore è di 5 minuti. Le risorse vengono conservate per cinque minuti, dopodiché si applicano le normali regole Cache-Control
per la risorsa.
L'uso della memorizzazione nella cache dei service worker può aiutarti a estendere la durata delle risorse di precaricamento oltre la finestra di cinque minuti.
Ad esempio, il portale sportivo italiano Virgilio Sport utilizza i service worker per precaricare i post più popolari nella propria home page. Utilizzano inoltre l'API Network Information per evitare il precaricamento per gli utenti che utilizzano una connessione 2G.
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 45% del numero di impressioni degli articoli.
Implementa la pre-memorizzazione nella cache con Workbox
Nella sezione seguente useremo Workbox per mostrare come implementare nel service worker diverse tecniche di memorizzazione nella cache che possono essere utilizzate come complemento di <link rel="prefetch">
o persino come sostituzione, delega completamente questa attività al service worker.
1. Prememorizzazione nella cache di pagine statiche e sottorisorse di pagina
La pre-memorizzazione nella cache è 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.
Memorizzazione nella cache delle pagine statiche
Per le pagine generate al momento della creazione (ad es. about.html
, contact.html
) o in siti completamente statici, è sufficiente aggiungere i documenti del sito all'elenco di pre-cache, 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 ...
]);
Prememorizzazione nella cache 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 le navigazioni in un sito di e-commerce, puoi utilizzare i tag <link rel="prefetch">
nelle pagine delle schede per precaricare le pagine dei dettagli dei prodotti per i primi prodotti di una pagina delle schede. Se hai già prememorizzato nella cache le risorse secondarie della pagina del prodotto, questo può rendere la navigazione ancora più veloce.
Per implementarlo:
- 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 pre-cache nel service worker:
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
// ... other entries ...
]);
2. Estendi la durata delle risorse di precaricamento
Come indicato in precedenza, <link rel="prefetch">
recupera e conserva 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 è di 5 minuti.
I service worker consentono di estendere la durata delle pagine di precaricamento, offrendo al contempo il vantaggio aggiuntivo di rendere le risorse disponibili per l'utilizzo offline.
Nell'esempio precedente, uno potrebbe integrare il <link rel="prefetch">
utilizzato per precaricare una pagina del prodotto con una strategia di memorizzazione nella cache del runtime di Workbox.
Per implementarlo:
- 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 di runtime 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 inattiva durante la riconvalida. In questa strategia, le pagine possono essere richieste in parallelo sia dalla cache sia dalla rete. La risposta proviene dalla cache, se disponibile, altrimenti dalla rete. La cache viene sempre aggiornata con le risposte della rete a ogni richiesta andata a buon fine.
3. Delegare il precaricamento 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, tuttavia, potrebbe essere meglio delegare completamente questa attività al service worker.
Ad esempio, per precaricare i primi prodotti in una pagina di schede di prodotto con rendering lato client, potrebbe essere necessario inserire diversi tag <link rel="prefetch">
in modo dinamico nella pagina, in base a una risposta dell'API. Ciò può temporaneamente richiedere tempo nel 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():
Il pacchetto Workbox Window semplifica questo tipo di comunicazione, astraendo molti dettagli della chiamata sottostante.
Il precaricamento con la finestra di Workbox può essere implementato nel seguente modo:
- Nella pagina: chiama il service worker che gli trasmette il tipo di messaggio e l'elenco di URL da precaricare:
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
}
});