Finora, ci sono stati solo menzioni e piccoli snippet di codice dei
l'interfaccia di Cache
.
Per utilizzare i service worker in modo efficace, è necessario adottare una o più strategie di memorizzazione nella cache,
il che richiede una certa familiarità con l'interfaccia Cache
.
Una strategia di memorizzazione nella cache è un'interazione tra l'evento fetch
di un service worker e l'interfaccia Cache
.
Il modo in cui viene scritta una strategia di memorizzazione nella cache dipende:
Ad esempio, potrebbe essere preferibile gestire le richieste per le risorse statiche in modo diverso rispetto ai documenti,
e questo influisce sul modo in cui è composta
la strategia di memorizzazione nella cache.
Prima di passare alle strategie,
soffermiamoci un attimo a parlare di cosa non è l'interfaccia di Cache
, che cos'è,
e un rapido resoconto di alcuni dei metodi che offre per gestire le cache dei service worker.
Interfaccia Cache
e cache HTTP
Se non hai mai lavorato con l'interfaccia Cache
,
potresti avere la tentazione di considerarlo uguale
o almeno relativi alla cache HTTP. Questo non è il caso.
- L'interfaccia
Cache
è un meccanismo di memorizzazione nella cache completamente separato dalla cache HTTP. - Qualsiasi cosa
Cache-Control
configurazione che utilizzi per influenzare la cache HTTP non influisce sugli asset archiviati nell'interfaccia diCache
.
È utile considerare le cache del browser come stratificate. La cache HTTP è una cache di basso livello gestita da coppie chiave-valore con istruzioni espresse nelle intestazioni HTTP.
Al contrario, l'interfaccia Cache
è una cache di alto livello basata su un'API JavaScript.
Questo offre maggiore flessibilità rispetto all'utilizzo di coppie chiave-valore HTTP relativamente semplici,
ed è la metà di ciò che rende possibili
le strategie di memorizzazione nella cache.
Alcuni importanti metodi dell'API per le cache dei service worker sono:
CacheStorage.open
per creare una nuova istanzaCache
.Cache.add
eCache.put
per archiviare le risposte di rete nella cache dei service worker.Cache.match
per individuare una risposta memorizzata nella cache in un'istanzaCache
.Cache.delete
per rimuovere una risposta memorizzata nella cache da un'istanzaCache
.
solo per citarne alcuni. Esistono altri metodi utili, ma queste sono quelle di base che vedrai più avanti in questa guida.
L'umile evento fetch
L'altra metà della strategia di memorizzazione nella cache è
Evento fetch
.
Finora in questa documentazione hai sentito parlare di "intercettazione delle richieste di rete",
e si verifica l'evento fetch
all'interno di un service worker:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(cacheName));
});
self.addEventListener('fetch', async (event) => {
// Is this a request for an image?
if (event.request.destination === 'image') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Respond with the image from the cache or from the network
return cache.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
// Add the network response to the cache for future visits.
// Note: we need to make a copy of the response to save it in
// the cache and use the original as the request response.
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
Questo è un esempio di giocattolo che puoi vedere in azione, offre un'idea di cosa possono fare i Service worker. Il codice riportato sopra fa quanto segue:
- Controlla la proprietà
destination
della richiesta per verificare se si tratta di una richiesta di immagine. - Se l'immagine si trova nella cache del service worker, pubblicala da lì. In caso contrario, recupera l'immagine dalla rete archiviare la risposta nella cache e restituire la risposta di rete.
- Tutte le altre richieste vengono passate attraverso il service worker senza interagire con la cache.
L'oggetto event
di un recupero contiene un
Proprietà request
che forniscono alcune informazioni utili per aiutarti a identificare il tipo di ogni richiesta:
url
, che è l'URL della richiesta di rete attualmente gestita dall'eventofetch
.method
, che è il metodo di richiesta (ad es.GET
oPOST
).mode
, che descrive la modalità della richiesta. Spesso viene utilizzato un valore'navigate'
per distinguere le richieste di documenti HTML da altre richieste.destination
, che descrive il tipo di contenuti richiesti in modo da evitare di utilizzare l'estensione del file dell'asset richiesto.
Ancora una volta, il nome del gioco è asincrono.
Ricorderai che l'evento install
offre un
event.waitUntil
che accetta una promessa e attende che venga risolta prima di procedere con l'attivazione.
L'evento fetch
offre una modalità simile
Metodo event.respondWith
che puoi utilizzare per restituire il risultato di un
Richiesta di fetch
o una risposta restituita dall'interfaccia Cache
match
.
Strategie di memorizzazione nella cache
Ora che hai acquisito familiarità con le istanze Cache
e il gestore di eventi fetch
,
puoi scoprire alcune strategie di memorizzazione nella cache dei service worker.
Sebbene le possibilità siano praticamente infinite,
questa guida illustrerà le strategie incluse in Workbox,
per farti un'idea di cosa succede all'interno di Workbox.
Solo cache
Iniziamo con una semplice strategia di memorizzazione nella cache che chiameremo "Solo cache". Semplicemente, quando il service worker controlla la pagina, le richieste con corrispondenza verranno trasferite solo nella cache. Ciò significa che gli asset memorizzati nella cache dovranno essere prememorizzati nella cache per renderli disponibili affinché il pattern funzioni. e che questi asset non vengano mai aggiornati nella cache fino all'aggiornamento del service worker.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
// Assets to precache
const precachedAssets = [
'/possum1.jpg',
'/possum2.jpg',
'/possum3.jpg',
'/possum4.jpg'
];
self.addEventListener('install', (event) => {
// Precache assets on install
event.waitUntil(caches.open(cacheName).then((cache) => {
return cache.addAll(precachedAssets);
}));
});
self.addEventListener('fetch', (event) => {
// Is this one of our precached assets?
const url = new URL(event.request.url);
const isPrecachedRequest = precachedAssets.includes(url.pathname);
if (isPrecachedRequest) {
// Grab the precached asset from the cache
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request.url);
}));
} else {
// Go to the network
return;
}
});
Sopra, un array di asset viene prememorizzato al momento dell'installazione.
Quando il service worker gestisce i recuperi,
verifichiamo se l'URL della richiesta gestito dall'evento fetch
si trova nell'array di asset prememorizzati nella cache.
In questo caso, prendiamo la risorsa dalla cache e ignoriamo la rete.
Altre richieste passano attraverso la rete,
e solo la rete.
Per vedere la strategia in azione,
guarda questa demo con la console aperta.
Solo rete
Il contrario di "Solo cache" è "Solo rete", in cui una richiesta viene fatta passare attraverso un service worker alla rete senza alcuna interazione con la cache del service worker. Si tratta di una buona strategia per garantire l'aggiornamento dei contenuti, ad esempio il markup. ma c'è un compromesso: non funzionerà mai quando l'utente è offline.
Se una richiesta passa attraverso la rete, significa semplicemente non chiamare event.respondWith
per una richiesta con corrispondenza.
Se vuoi essere esplicito,
puoi schiacciare uno return;
vuoto nel callback dell'evento fetch
per le richieste che vuoi passare alla rete.
Ecco cosa succede nella sezione "Solo cache" per le richieste che non sono prememorizzate nella cache.
Prima memorizza nella cache, poi torna alla rete
È in questa strategia che le cose diventano un po' più coinvolte. Per le richieste con corrispondenza, la procedura è la seguente:
- La richiesta raggiunge la cache. Se l'asset si trova nella cache, pubblicalo da lì.
- Se la richiesta non si trova nella cache, accedi alla rete.
- Al termine della richiesta di rete, aggiungila alla cache per poi restituire la risposta dalla rete.
Ecco un esempio di questa strategia, che puoi testare in una demo dal vivo:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a request for an image
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the cache first
return cache.match(event.request.url).then((cachedResponse) => {
// Return a cached response if we have one
if (cachedResponse) {
return cachedResponse;
}
// Otherwise, hit the network
return fetch(event.request).then((fetchedResponse) => {
// Add the network response to the cache for later visits
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
Anche se questo esempio riguarda solo le immagini, questa è un'ottima strategia da applicare a tutti gli asset statici (come CSS, JavaScript, immagini e caratteri), in particolare quelli con versione hash. Offre un aumento di velocità per le risorse immutabili, aggirando eventuali controlli di aggiornamento dei contenuti con il server su cui la cache HTTP potrebbe essere avviata. Ma soprattutto, tutti gli asset memorizzati nella cache saranno disponibili offline.
Prima sulla rete, poi tornando alla cache
Se capoverti "Prima cache, poi rete" in testa, si verifica il messaggio "Prima la rete, poi la cache" strategia, che è il suo significato:
- Devi prima andare alla rete per richiedere una richiesta e inserire la risposta nella cache.
- Se in seguito sarai offline, dovrai scaricare la versione più recente della risposta nella cache.
Questa strategia è ideale per le richieste HTML o API quando mentre sei online, vuoi la versione più recente di una risorsa, vogliono concedere l'accesso offline alla versione più recente disponibile. Ecco come potrebbe apparire quando viene applicato a richieste di HTML:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a navigation request
if (event.request.mode === 'navigate') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the network first
return fetch(event.request.url).then((fetchedResponse) => {
cache.put(event.request, fetchedResponse.clone());
return fetchedResponse;
}).catch(() => {
// If the network is unavailable, get
return cache.match(event.request.url);
});
}));
} else {
return;
}
});
Puoi provare questa funzionalità in una demo. Innanzitutto, vai alla pagina. Potrebbe essere necessario ricaricare prima che la risposta HTML venga inserita nella cache. Poi, negli strumenti per sviluppatori, simulare una connessione offline, e ricaricarla. L'ultima versione disponibile verrà pubblicata immediatamente dalla cache.
Nei casi in cui la funzionalità offline è importante, ma è necessario bilanciare questa funzionalità con l'accesso alla versione più recente di un po' di markup o di dati delle API, "Prima sulla rete, poi sulla cache" è una strategia efficace per raggiungere questo obiettivo.
Inattiva-durante la riconvalida
Tra le strategie che abbiamo trattato finora, "Inibito durante la riconvalida" è la più complessa. Per certi versi è simile alle ultime due strategie, ma la procedura dà priorità alla velocità di accesso a una risorsa, e allo stesso tempo aggiorna il video in background. Questa strategia è simile a:
- Durante la prima richiesta di un asset, recuperalo dalla rete, nella cache e restituire la risposta di rete.
- Nelle richieste successive, pubblica prima l'asset dalla cache e poi "in background". richiedila nuovamente alla rete e aggiorna la voce della cache dell'asset.
- Per le richieste successive, riceverai l'ultima versione recuperata dalla rete che era stata inserita nella cache nel passaggio precedente.
Si tratta di una strategia eccellente per ciò che è un po' importante da tenere aggiornati, ma non sono cruciali. Pensa agli elementi come agli avatar per un sito di social media. Vengono aggiornate quando gli utenti lo fanno, ma la versione più recente non è strettamente necessaria per ogni richiesta.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request).then((cachedResponse) => {
const fetchedResponse = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchedResponse;
});
}));
} else {
return;
}
});
Puoi vedere come funziona
un'altra demo dal vivo,
in particolare se fai attenzione alla scheda Rete
negli strumenti per sviluppatori del browser,
e il relativo visualizzatore CacheStorage
(se gli strumenti per sviluppatori del tuo browser dispongono di questo strumento).
Avanti a Workbox!
Questo documento racchiude la nostra revisione dell'API del service worker, nonché le API correlate, il che significa che hai imparato abbastanza su come utilizzare direttamente i service worker per iniziare ad armeggiare con Workbox.