Signatur
Beschreibung
Die schreibgeschützte Eigenschaft navigator.serviceWorker.ready gibt ein Promise zurück. Es erfüllt sich mit der ServiceWorkerRegistration, deren Geltungsbereich (scope) die aktuelle Seite umfasst und die einen aktiven Worker besitzt (registration.active ist dann nicht null). Damit lässt sich Code, der einen einsatzbereiten Service Worker braucht, sauber verzögern.
Typische Einsatzfälle sind Funktionen, die nur über eine aktive Registrierung funktionieren: Push-Abonnements mit registration.pushManager.subscribe(), Hintergrund-Synchronisation mit registration.sync.register(), Benachrichtigungen per registration.showNotification() oder Nachrichten an registration.active.postMessage().
Wichtig: Das Promise wird niemals abgelehnt. Wenn keine passende Registrierung existiert oder die Registrierung fehlschlägt, bleibt es für immer ausstehend (pending). Es ist also kein Fehlerindikator. Außerdem steht es nicht dafür, dass die Seite schon von diesem Worker kontrolliert wird. Dafür ist navigator.serviceWorker.controller bzw. das Ereignis controllerchange zuständig.
Rückgabewert
ServiceWorkerRegistration für die aktuelle Seite erfüllt. Es liefert bei jedem Zugriff dasselbe Promise-Objekt, solange sich die Registrierung nicht ändert, und wird nie abgelehnt.Beispiele
Registrieren und auf den aktiven Worker warten
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.catch((err) => console.error('Registrierung fehlgeschlagen:', err));
const registration = await navigator.serviceWorker.ready;
console.log('Aktiver Worker:', registration.active.state);
console.log('Scope:', registration.scope);
}
Push-Benachrichtigungen abonnieren
const urlBase64ToUint8Array = (base64) => {
const padding = '='.repeat((4 - (base64.length % 4)) % 4);
const raw = atob((base64 + padding).replace(/-/g, '+').replace(/_/g, '/'));
return Uint8Array.from(raw, (c) => c.charCodeAt(0));
};
const subscribeToPush = async (vapidPublicKey) => {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey)
});
await fetch('/api/push/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
return subscription;
};
Nachricht an den Worker senden – mit Timeout gegen ewiges Warten
const withTimeout = (promise, ms) => Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Kein aktiver Service Worker')), ms))
]);
try {
const registration = await withTimeout(navigator.serviceWorker.ready, 5000);
registration.active.postMessage({ type: 'CACHE_URLS', urls: ['/offline.html'] });
console.log('Nachricht gesendet');
} catch (err) {
console.warn(err.message);
}
// Wichtig · Fallstricke
- Keine Ablehnung:
readywird nie abgelehnt. Schlägtregister()fehl oder liegt die Seite außerhalb jedes Scopes, bleibt einawaitfür immer hängen. Fehler behandelt man amregister()-Promise, und bei Bedarf sichert man mit einem Timeout ab (siehe Beispiel 3). - Aktiv heißt nicht kontrollierend: Beim ersten Laden ist
navigator.serviceWorker.controlleroft nochnull, obwohlreadyschon erfüllt ist. Abhilfe:clients.claim()im Worker oder aufcontrollerchangewarten. - Sicherer Kontext nötig: Service Worker gibt es nur über HTTPS (oder
localhost). In privaten Fenstern mancher Browser (z. B. älteres Firefox) istnavigator.serviceWorkerundefined. Deshalb vorher mit'serviceWorker' in navigatorprüfen. - Scope beachten: Ein Worker unter
/app/sw.jsgilt standardmäßig nur für/app/. Seiten außerhalb davon erhalten überreadykeine Registrierung. - Top-Level-
awaitfunktioniert nur in ES-Modulen (<script type="module">).