Strategieën voor het cachen van servicemedewerkers

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 de Cache 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 ​​nieuwe Cache instantie te maken.
  • Cache.add en Cache.put om netwerkreacties op te slaan in de cache van een servicewerker.
  • Cache.match om een ​​in de cache opgeslagen antwoord in een Cache instantie te lokaliseren.
  • Cache.delete om een ​​in de cache opgeslagen antwoord van een Cache instantie te verwijderen.

Dit zijn er maar een paar. Er zijn nog andere handige 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:

  1. Inspecteer de destination van het verzoek om te zien of dit een afbeeldingsverzoek is.
  2. 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.
  3. 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 de fetch gebeurtenis.
  • method , wat de verzoekmethode is (bijvoorbeeld GET of POST ).
  • 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

Toont de stroom van pagina, naar servicemedewerker, naar 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

Toont de stroom van pagina, naar servicemedewerker, naar 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

Toont de stroom van de pagina, naar de servicemedewerker, naar de cache en vervolgens naar het netwerk als deze zich niet in de cache bevindt.

Bij deze strategie worden de zaken wat ingewikkelder. Voor matchingverzoeken gaat het proces als volgt:

  1. Het verzoek raakt de cache. Als het item zich in de cache bevindt, serveer het dan vanaf daar.
  2. Als het verzoek niet in de cache staat, ga dan naar het netwerk.
  3. 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

Toont de stroom van de pagina, naar de servicemedewerker, naar het netwerk en vervolgens naar de cache als het netwerk niet beschikbaar is.

Als je 'Eerste cache, tweede cache' op zijn kop zou zetten, kom je terecht bij de strategie 'Eerste netwerk, tweede cache', en zo klinkt het ook:

  1. Je gaat eerst naar het netwerk voor een verzoek en plaatst het antwoord in de cache.
  2. 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 recente 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

Toont de stroom van pagina, naar servicemedewerker, naar cache en vervolgens van netwerk naar cache.

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:

  1. 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.
  2. 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.
  3. 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 dingen 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 Workbox!

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!