Signatur
Beschreibung
Wenn ein Service Worker zum ersten Mal registriert wird, steuert er Seiten, die bereits geöffnet sind, nicht automatisch. Erst beim nächsten Laden laufen deren Netzwerkanfragen über den Worker. Mit self.clients.claim() übernimmt der aktive Service Worker die Kontrolle über alle Clients (Fenster, Tabs, Worker) in seinem scope sofort. Deren navigator.serviceWorker.controller wird gesetzt und in jedem betroffenen Client wird das Ereignis controllerchange ausgelöst.
Üblicherweise ruft man claim() im activate-Ereignis auf, eingebettet in event.waitUntil(). Zusammen mit self.skipWaiting() im install-Ereignis sorgt das dafür, dass eine neue Version des Service Workers ohne Wartezeit aktiv wird und alle offenen Tabs übernimmt.
Zu beachten: Die Seiten wurden eventuell mit Ressourcen aus einer älteren Version (oder ganz ohne Service Worker) geladen. Wenn der neue Worker andere Cache-Strategien oder API-Versionen nutzt, kann es zu Inkonsistenzen kommen. Setze claim() daher bewusst ein, wenn die neue Version mit bereits geladenen Seiten verträglich ist.
Rückgabewert
Promise, das sich mit undefined erfüllt, sobald der Service Worker alle passenden Clients übernommen hat. Es wird mit einem InvalidStateError (DOMException) abgelehnt, wenn der Worker nicht der aktive Worker seiner Registrierung ist.Beispiele
Clients direkt beim Aktivieren übernehmen
// sw.js
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim());
});
Sofortiges Update mit skipWaiting() und claim()
// sw.js
const CACHE = 'app-v2';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE)
.then((cache) => cache.addAll(['/', '/app.js', '/styles.css']))
.then(() => self.skipWaiting())
);
});
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
// Alte Caches aufräumen
const keys = await caches.keys();
await Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)));
// Danach alle offenen Tabs übernehmen
await self.clients.claim();
console.log('Service Worker steuert jetzt alle Clients');
})());
});
Übernahme auf der Seite erkennen (controllerchange)
// main.js (Seite)
if ('serviceWorker' in navigator) {
navigator.serviceWorker.addEventListener('controllerchange', () => {
console.log('Neuer Controller:', navigator.serviceWorker.controller?.scriptURL);
});
await navigator.serviceWorker.register('/sw.js');
console.log('Gesteuert?', Boolean(navigator.serviceWorker.controller));
}
Alle Clients nach der Übernahme benachrichtigen
// sw.js
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
await self.clients.claim();
const list = await self.clients.matchAll({ type: 'window' });
list.forEach((client) => client.postMessage({ type: 'SW_ACTIVATED' }));
})());
});
// Wichtig · Fallstricke
- Nur im aktiven Worker: Ein Aufruf in
install, also bevor der Worker aktiv ist, führt zu einem abgelehnten Promise mitInvalidStateError. Rufeclaim()deshalb inactivateoder später auf. - Immer mit
waitUntil(): Ohneevent.waitUntil()kann der Browser den Worker beenden, bevor die Übernahme abgeschlossen ist. - Gemischte Versionen: Bereits geladene Seiten laufen danach mit einem Service Worker, der möglicherweise andere Caches oder Routen erwartet. Bei tiefgreifenden Änderungen ist ein Neuladen der Seite, z. B. über
controllerchange, oft die sicherere Lösung. - Scope: Übernommen werden nur Clients, deren URL im
scopeder Registrierung liegt und die denselben Ursprung (Origin) haben. - Kompatibilität: Wird von allen modernen Browsern unterstützt. Service Worker funktionieren nur in sicheren Kontexten (HTTPS oder
localhost). Bei einem Hard-Reload (Shift+Neu laden) umgeht die Seite den Service Worker, undcontrollerbleibtnull.