Stephan Böni - Service Worker Cache

Service Worker Caching

Service Worker Caching

Während Service Worker und PWAs zu Standards moderner Webanwendungen werden, ist das Ressourcen-Caching komplexer als je zuvor. In diesem Beitrag werden die wichtigsten Aspekte des Browser-Cachings behandelt.

Cache zuerst und was dann?

Analog zum Browser-Cache ist die Strategie, zuerst im eigenen Cache nach der gefragten Ressource zu suchen, für die meisten Anwendungsfälle passend. Bauen wir also auf dieses Szenario auf und vervollständigen die Kaskade.

Wenn die Ressource noch nicht im Cache ist, gibt es zwei Möglichkeiten: A, wir haben eine Netzwerkverbindung zum Server oder B, wir sind offline. Trifft letzteres zu, also B, zeigen wir eine Offline-Seite an. Wie du einen Service Worker installierst und eine Offline-Seite bereitstellst, findest du hier.

Im Normalfall trifft jedoch A zu und wir fragen den Server nach der Ressource. Dazu gibt es wiederum zwei Möglichkeiten, auf die wir näher eingehen sollten.

Bis der Service Worker geladen, installiert und aktiviert ist, können bis zu fünfzig Millisekunden verstreichen. Aus Performance-Gründen wartet der Browser daher mit seiner ersten Anfrage nicht auf den Service Worker. Wir sollten aber beim Aktivieren des Service Workers die Antwort auf diese Erstanfrage berücksichtigen, indem wir die Unterstützung dieses Preloads einschalten.

service-worker.js // Call Activate Event self.addEventListener('activate', event => { console.log('Service Worker: Activated'); event.waitUntil( (async () => { // enable navigation preload await self.registration.navigationPreload.enable(); // remove unwanted caches caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cache => { if (cache !== cacheName) return caches.delete(cache); }) ); }); })() ); // tell the active service worker to take control of the page immediately self.clients.claim(); });

Jetzt können wir diesen Preload abfangen, eine Kopie davon in den Cache legen und dann die Ressource zur Anzeige geben.

Diese Erstanfrage und folgedessen auch die Anwort enthält aber nicht alles, sondern nur die Navigation, also die initiale Seite ohne beispielsweise Bilder, die darin geladen werden. Alles weitere müssen wir also noch erfragen. Und falls der Browser gar keine Erstanfrage gesendet hat, müssen wir alles erfragen. Auch hier fangen wir die Antwort ab und erstellen eine Kopie für den Cache, bevor wir sie zur Anzeige weitergeben.

service-worker.js // Call Fetch Event self.addEventListener('fetch', event => { const requestURL = new URL(event.request.url); if ((requestURL.origin == location.origin) && (event.request.method != 'POST')) { event.respondWith( caches.open(cacheName) .then((cache) => { return cache.match(event.request) .then((cachedResponse) => { // frist try to return the page from cache if (cachedResponse) { return cachedResponse; } // if we are offline display the offline page if (!navigator.onLine) { return caches.match(offlineUrl); } // then try to return the preload and add the cache if ((event.request.mode === 'navigate') && event.preloadResponse) { return Promise.resolve(event.preloadResponse) .then((preloadResponse) => { cache.put(event.request, preloadResponse.clone()); return preloadResponse; }) } // finaly try the network and add the cache return fetch(event.request) .then((networkResponse) => { cache.put(event.request, networkResponse.clone()); return networkResponse; }) }) .catch(() => { // if all fails display the offline page again return caches.match(offlineUrl); }) }) ); } });

Das sieht nun zumindest vorderhand alles gut aus.

Service Worker Cache-Update

Service Worker Cache-Update

Wenn du deine Website aktualisierst, wirst du feststellen, dass weiterhin der alte Inhalt aus dem Cache geladen wird, maixmal für die nächsten neunzig Tage. So lange bleibt standardmässig der Cache gültig.

Das reicht dir nicht? Dann ist es Zeit für eine Cache-Update-Strategie.

Cache aktualisieren