Tot nu toe zijn er alleen vermeldingen en kleine codefragmenten van de Cache
interface geweest. Om servicemedewerkers effectief in te zetten, is het noodzakelijk om een of meer cachingstrategieën toe te passen, waarvoor enige bekendheid met de Cache
interface vereist is.
Een cachingstrategie is een interactie tussen fetch
van een servicemedewerker en de Cache
interface. Hoe een cachingstrategie wordt geschreven hangt ervan af; Het kan bijvoorbeeld de voorkeur verdienen om aanvragen voor statische assets anders af te handelen dan documenten, en dit heeft invloed op de manier waarop een cachingstrategie wordt samengesteld.
Voordat we ingaan op de strategieën zelf, nemen we even de tijd om te praten over wat de Cache
interface niet is, wat het wel is, en een kort overzicht van enkele van de methoden die het biedt om caches van servicemedewerkers te beheren.
De Cache
interface versus de HTTP-cache
Als je nog niet eerder met de Cache
interface hebt gewerkt, kan het verleidelijk zijn om deze als hetzelfde te beschouwen als, of op zijn minst gerelateerd aan de HTTP-cache. Dit is niet het geval.
- De
Cache
interface is een caching-mechanisme dat volledig gescheiden is van de HTTP-cache. - Welke
Cache-Control
configuratie u ook gebruikt om de HTTP-cache te beïnvloeden, heeft geen invloed op welke assets in deCache
interface worden opgeslagen.
Het helpt om browsercaches als gelaagd te beschouwen. De HTTP-cache is een cache op laag niveau die wordt aangestuurd door sleutel-waardeparen met richtlijnen uitgedrukt in HTTP-headers.
De Cache
interface is daarentegen een cache op hoog niveau, aangedreven door een JavaScript-API. Dit biedt meer flexibiliteit dan bij het gebruik van relatief simplistische HTTP-sleutelwaardeparen, en is de helft van wat caching-strategieën mogelijk maakt. Enkele belangrijke API-methoden rond caches van servicemedewerkers zijn:
-
CacheStorage.open
om een nieuweCache
instantie te maken. -
Cache.add
enCache.put
om netwerkreacties op te slaan in de cache van een servicewerker. -
Cache.match
om een in de cache opgeslagen antwoord in eenCache
instantie te lokaliseren. -
Cache.delete
om een in de cache opgeslagen antwoord van eenCache
instantie te verwijderen.
Dit zijn er maar een paar. Er zijn nog meer nuttige methoden, maar dit zijn de basismethoden die u verderop in deze handleiding zult zien.
Het bescheiden fetch
De andere helft van een cachingstrategie is de fetch
gebeurtenis van de servicemedewerker. Tot nu toe heb je in deze documentatie iets gehoord over het "onderscheppen van netwerkverzoeken", en dit gebeurt in de fetch
gebeurtenis in een servicemedewerker:
// 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;
}
});
Dit is een speelgoedvoorbeeld – en je kunt het zelf in actie zien – maar het geeft een idee van wat servicemedewerkers kunnen doen. De bovenstaande code doet het volgende:
- Inspecteer de
destination
van het verzoek om te zien of dit een afbeeldingsverzoek is. - Als de afbeelding zich in de cache van de servicemedewerker bevindt, kunt u deze vanaf daar bedienen. Als dit niet het geval is, haalt u de afbeelding op van het netwerk, slaat u het antwoord op in de cache en retourneert u het netwerkantwoord.
- Alle andere verzoeken worden doorgegeven via de servicemedewerker zonder interactie met de cache.
Het event
van een fetch bevat een request
met enkele nuttige stukjes informatie om u te helpen het type van elk verzoek te identificeren:
-
url
, wat de URL is voor het netwerkverzoek dat momenteel wordt afgehandeld door defetch
gebeurtenis. -
method
, wat de verzoekmethode is (bijvoorbeeldGET
ofPOST
). -
mode
, die de modus van het verzoek beschrijft. Vaak wordt de waarde'navigate'
gebruikt om verzoeken om HTML-documenten te onderscheiden van andere verzoeken. -
destination
, die het type inhoud beschrijft dat wordt aangevraagd op een manier die vermijdt dat de bestandsextensie van het aangevraagde item wordt gebruikt.
Nogmaals, asynchronie is de naam van het spel. U zult zich herinneren dat de install
gebeurtenis een event.waitUntil
-methode biedt die een belofte aanneemt en wacht tot deze is opgelost voordat u doorgaat met activeren. De fetch
gebeurtenis biedt een vergelijkbare event.respondWith
-methode die u kunt gebruiken om het resultaat te retourneren van een asynchrone fetch
of een antwoord dat wordt geretourneerd door de match
methode van de Cache
interface.
Caching-strategieën
Nu u een beetje bekend bent met Cache
instanties en de gebeurtenishandler fetch
, bent u klaar om in enkele cachingstrategieën voor servicemedewerkers te duiken. Hoewel de mogelijkheden vrijwel eindeloos zijn, blijft deze handleiding bij de strategieën die bij Workbox worden geleverd, zodat u een idee krijgt van wat er in de interne onderdelen van Workbox gebeurt.
Alleen cache
Laten we beginnen met een eenvoudige cachingstrategie die we 'Alleen cache' noemen. Het is precies dat: wanneer de servicemedewerker de controle over de pagina heeft, gaan overeenkomende verzoeken alleen naar de cache. Dit betekent dat alle in de cache opgeslagen assets vooraf in de cache moeten worden geplaatst om beschikbaar te zijn om het patroon te laten werken, en dat deze assets nooit in de cache zullen worden bijgewerkt totdat de servicemedewerker is bijgewerkt.
// 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;
}
});
Hierboven wordt tijdens de installatie een reeks assets vooraf in de cache geplaatst. Wanneer de servicemedewerker de ophaalacties afhandelt, controleren we of de aanvraag-URL die door de fetch
wordt afgehandeld, zich in de reeks vooraf in de cache opgeslagen assets bevindt. Als dat zo is, halen we de bron uit de cache en slaan we het netwerk over. Andere verzoeken gaan door naar het netwerk, en alleen naar het netwerk. Om deze strategie in actie te zien, bekijk je deze demo met je console open.
Alleen netwerk
Het tegenovergestelde van "Alleen cache" is "Alleen netwerk", waarbij een verzoek via een servicemedewerker naar het netwerk wordt doorgegeven zonder enige interactie met de cache van de servicemedewerker. Dit is een goede strategie om de versheid van de inhoud te garanderen (denk aan markup), maar de wisselwerking is dat dit nooit zal werken als de gebruiker offline is.
Ervoor zorgen dat een verzoek wordt doorgegeven aan het netwerk betekent alleen dat u event.respondWith
niet aanroept voor een overeenkomend verzoek. Als je expliciet wilt zijn, kun je een lege return;
in uw fetch
terugbellen voor verzoeken die u wilt doorgeven aan het netwerk. Dit is wat er gebeurt in de strategiedemo 'Alleen cache' voor aanvragen die niet vooraf in de cache zijn geplaatst.
Eerst cachen en terugvallen op het netwerk
Bij deze strategie worden de zaken wat ingewikkelder. Voor matchingverzoeken gaat het proces als volgt:
- Het verzoek raakt de cache. Als het item zich in de cache bevindt, serveer het dan vanaf daar.
- Als het verzoek niet in de cache staat, ga dan naar het netwerk.
- Zodra het netwerkverzoek is voltooid, voegt u het toe aan de cache en retourneert u het antwoord van het netwerk.
Hier is een voorbeeld van deze strategie, die u kunt testen in een live demo :
// 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;
}
});
Hoewel dit voorbeeld alleen betrekking heeft op afbeeldingen, is dit een goede strategie om toe te passen op alle statische elementen (zoals CSS, JavaScript, afbeeldingen en lettertypen), vooral op hash-versies. Het biedt een snelheidsboost voor onveranderlijke assets door controles op de versheid van de inhoud te omzeilen met de server waarop de HTTP-cache kan starten. Wat nog belangrijker is, is dat alle in de cache opgeslagen assets offline beschikbaar zullen zijn.
Netwerk eerst, terugvallend op de cache
Als je 'Eerst cache, dan netwerk tweede' op zijn kop zou zetten, krijg je de strategie 'Netwerk eerst, cache tweede', en zo klinkt het ook:
- Je gaat eerst naar het netwerk voor een verzoek en plaatst het antwoord in de cache.
- Als u op een later moment offline bent, valt u terug op de nieuwste versie van dat antwoord in de cache.
Deze strategie is ideaal voor HTML- of API-verzoeken wanneer u, terwijl u online bent, de meest recente versie van een bron wilt hebben, maar toch offline toegang wilt geven tot de meest recent beschikbare versie. Hier ziet u hoe dat eruit zou kunnen zien als het wordt toegepast op verzoeken om 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;
}
});
U kunt dit uitproberen in een demo . Ga eerst naar de pagina. Mogelijk moet u opnieuw laden voordat het HTML-antwoord in de cache wordt geplaatst. Simuleer vervolgens in uw ontwikkelaarstools een offline verbinding en laad opnieuw. De laatst beschikbare versie wordt onmiddellijk vanuit de cache geserveerd.
In situaties waarin offline mogelijkheden belangrijk zijn, maar je die mogelijkheden in evenwicht moet brengen met toegang tot de meest recente versie van een stukje markup- of API-gegevens, is 'Netwerk eerst, daarna cache' een solide strategie om dat doel te bereiken.
Verouderd terwijl opnieuw gevalideerd
Van de strategieën die we tot nu toe hebben besproken, is ‘verouderen terwijl opnieuw valideren’ de meest complexe. Het lijkt in sommige opzichten op de laatste twee strategieën, maar de procedure geeft prioriteit aan de snelheid van toegang tot een bron, terwijl deze ook op de achtergrond up-to-date wordt gehouden. Deze strategie gaat ongeveer als volgt:
- Bij de eerste aanvraag voor een asset haalt u deze op van het netwerk, plaatst u deze in de cache en retourneert u het netwerkantwoord.
- Bij volgende verzoeken dient u de asset eerst vanuit de cache te leveren, vervolgens 'op de achtergrond', opnieuw aan te vragen via het netwerk en de cache-invoer van de asset bij te werken.
- Voor verzoeken daarna ontvangt u de laatste versie die is opgehaald van het netwerk en die in de vorige stap in de cache is geplaatst.
Dit is een uitstekende strategie voor zaken die belangrijk zijn om up-to-date te blijven, maar niet cruciaal zijn. Denk aan dingen als avatars voor een sociale-mediasite. Ze worden bijgewerkt wanneer gebruikers daartoe in staat zijn, maar de nieuwste versie is niet strikt noodzakelijk voor elk verzoek.
// 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;
}
});
Je kunt dit in actie zien in nog een andere live demo , vooral als je aandacht besteedt aan het netwerktabblad in de ontwikkelaarstools van je browser en de CacheStorage
viewer (als de ontwikkelaarstools van je browser zo'n tool hebben).
Op naar Werkbox!
Dit document rondt onze bespreking van de API van servicemedewerkers af, evenals de bijbehorende API's, wat betekent dat u genoeg hebt geleerd over hoe u servicemedewerkers rechtstreeks kunt gebruiken om aan Workbox te gaan sleutelen!