// apis · Web Platform Advent #4
Service Worker: Caching, Offline-Betrieb und Updates erklärt
Ein praktischer Leitfaden zu Service Workern — einen registrieren, der Install-/Activate-Lebenszyklus, die Cache-API, eine Seite offline ausliefern und Updates sicher ausrollen.
Ein Service Worker ist ein Skript, das der Browser im Hintergrund ausführt, getrennt von Ihrer Seite. Er sitzt zwischen Ihrer App und dem Netzwerk wie ein programmierbarer Proxy: Er kann Anfragen abfangen, sie aus einem Cache beantworten und Ihre Website am Laufen halten, selbst wenn der Nutzer offline ist. Er ist die Grundlage von Progressive Web Apps.
Zwei Grundregeln vor allem anderen. Ein Service Worker läuft nur über HTTPS (oder localhost während der Entwicklung), und er hat keinen Zugriff auf das DOM — er kommuniziert mit Seiten über Events und Nachrichten, nicht indem er document berührt.
Einen Service Worker registrieren
Sie registrieren den Worker aus Ihrem normalen Seitenskript. Prüfen Sie zuerst die Verfügbarkeit der Funktion, dann verweisen Sie den Browser auf die Skriptdatei:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then((reg) => console.log('Scope:', reg.scope))
.catch((err) => console.error('SW failed:', err));
});
} Der Speicherort der Datei ist wichtig: Ein Worker unter /sw.js steuert den gesamten Origin, während einer unter /app/sw.js nur Seiten unter /app/ steuert. Diese Grenze ist sein Scope.
Der Lebenszyklus: install und activate
Ein Service Worker hat ein eigenes Leben, unabhängig von der Seite. Die beiden Events, die Sie am meisten interessieren, sind install (wird einmal ausgelöst, ein guter Ort, um Assets vorzucachen) und activate (ein guter Ort, um alte Caches aufzuräumen):
const CACHE = 'site-v1';
const ASSETS = ['/', '/index.html', '/styles.css', '/app.js', '/offline.html'];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE).then((cache) => cache.addAll(ASSETS))
);
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))
)
);
}); Der Aufruf von event.waitUntil() teilt dem Browser mit, die Phase erst als abgeschlossen zu betrachten, wenn Ihr Promise erfüllt ist — andernfalls könnte er den Worker mitten in der Arbeit abbrechen.
Anfragen mit fetch abfangen
Das fetch-Event ist der Ort, an dem die Magie passiert. Sie entscheiden, was jede Anfrage zurückgibt. Eine gängige, sichere Strategie ist Cache-First mit Netzwerk-Fallback:
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request);
})
);
}); Um eine eigene Offline-Seite anzuzeigen, wenn sowohl der Cache als auch das Netzwerk fehlschlagen, fügen Sie ein catch hinzu:
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request).catch(() => caches.match('/offline.html'))
);
}); Caching-Strategien auf einen Blick
| Strategie | Verhalten | Gut für |
|---|---|---|
| Cache-First | Cache ausliefern, auf Netzwerk zurückfallen | Statische Assets (CSS, JS, Schriften) |
| Network-First | Netzwerk versuchen, auf Cache zurückfallen | HTML, sich ändernde API-Daten |
| Stale-While-Revalidate | Cache ausliefern, ihn im Hintergrund aktualisieren | Avatare, Feeds, Inhaltslisten |
Updates ausrollen, ohne Nutzer zu beeinträchtigen
Wenn Sie sw.js ändern, erkennt der Browser die neuen Bytes und installiert den neuen Worker, aber er bleibt wartend, bis jeder Tab, der den alten verwendet, geschlossen ist. Das verhindert, dass zwei Versionen gleichzeitig laufen. Um früher zu übernehmen, rufen Sie self.skipWaiting() in install und clients.claim() in activate auf — aber tun Sie das nur, wenn Sie sicher sind, dass die neue Version mit bereits geöffneten Seiten kompatibel ist.
Erhöhen Sie immer den Cache-Namen (site-v1 → site-v2), wenn sich Assets ändern. Der obige activate-Handler löscht dann den veralteten Cache, sodass Nutzer nie eine Mischung aus alten und neuen Dateien erhalten.
Das ist die gesamte Kernschleife: registrieren, beim install vorcachen, beim activate aufräumen und Anfragen beim fetch beantworten. Beginnen Sie mit einer Cache-First-Strategie für statische Dateien und einer Network-First-Strategie für Ihr HTML, und Sie haben eine Website, die bei wiederholten Besuchen sofort lädt und eine abgebrochene Verbindung übersteht.