Start · Sprachen · JavaScript · Referenz · ServiceWorkerGlobalScope.skipWaiting()

ServiceWorkerGlobalScope.skipWaiting()

Methode

Lässt einen neu installierten, wartenden Service Worker sofort aktiv werden, ohne dass zuvor alle Tabs mit dem alten Worker geschlossen werden müssen.

seit JavaScript Baseline: alle modernen Browser (Chrome 40+, Firef Kategorie: webapi

Signatur

ServiceWorkerGlobalScope.prototype.skipWaiting()

Beschreibung

Normalerweise bleibt ein neu installierter Service Worker im Zustand waiting, solange noch mindestens ein Client (Tab, Fenster, iframe) vom bisher aktiven Worker kontrolliert wird. Erst wenn alle diese Clients geschlossen oder weg-navigiert sind, wird die neue Version aktiviert. skipWaiting() überspringt diese Wartephase: Der neue Worker wird aktiviert, sobald er fertig installiert ist.

Die Methode wird im Kontext des Service Workers aufgerufen (self.skipWaiting()). Das geschieht meist im install-Event oder, wenn die Seite den Nutzer vorher fragen soll, in einem message-Handler, sobald die Seite ein „Jetzt aktualisieren“-Signal schickt. Der Aufruf kann jederzeit erfolgen. Wirksam wird er aber nur, wenn gerade ein Worker installiert wird oder bereits wartet.

Oft wird skipWaiting() zusammen mit Clients.claim() im activate-Event benutzt. Dann übernimmt der neue Worker auch die bereits geöffneten Seiten sofort, statt erst beim nächsten Laden.

Achtung: Nach skipWaiting() können geöffnete Seiten, die noch mit altem HTML oder JavaScript laufen, auf einmal von einem neuen Worker mit neuen Caches bedient werden. Ohne passende Strategie (z. B. Seite neu laden über das controllerchange-Event) kann es dadurch zu Versionskonflikten kommen.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das sofort mit undefined erfüllt wird, sobald der Aufruf angenommen wurde. Es wartet nicht, bis die Aktivierung abgeschlossen ist.

Beispiele

Neue Version sofort aktivieren (install + activate)

// sw.js
const CACHE = 'app-v2';

self.addEventListener('install', (event) => {
  // Wartephase überspringen, das Ergebnis muss nicht abgewartet werden
  self.skipWaiting();
  event.waitUntil(
    caches.open(CACHE).then((cache) => cache.addAll(['/', '/app.js', '/style.css']))
  );
});

self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    // Alte Caches entfernen
    const keys = await caches.keys();
    await Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)));
    // Bereits geöffnete Seiten sofort übernehmen
    await self.clients.claim();
    console.log('Neuer Service Worker aktiv');
  })());
});
Neuer Service Worker aktiv

Update erst nach Bestätigung durch den Nutzer

// sw.js
self.addEventListener('message', (event) => {
  if (event.data?.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

// main.js (Seite)
const reg = await navigator.serviceWorker.register('/sw.js');

const promptUpdate = (worker) => {
  if (confirm('Neue Version verfügbar. Jetzt aktualisieren?')) {
    worker.postMessage({ type: 'SKIP_WAITING' });
  }
};

if (reg.waiting) promptUpdate(reg.waiting);

reg.addEventListener('updatefound', () => {
  const newWorker = reg.installing;
  newWorker.addEventListener('statechange', () => {
    if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
      promptUpdate(newWorker);
    }
  });
});

Seite nach dem Worker-Wechsel neu laden

// main.js – nach skipWaiting() wechselt der Controller
let reloading = false;
navigator.serviceWorker.addEventListener('controllerchange', () => {
  if (reloading) return; // Endlosschleife verhindern
  reloading = true;
  console.log('Neuer Controller – lade neu');
  window.location.reload();
});
Neuer Controller – lade neu

// Wichtig · Fallstricke

  • Versionskonflikte: Offene Tabs laufen nach dem Wechsel mit altem Code weiter, ihre Anfragen gehen aber schon an den neuen Worker. Wenn sich Cache-Namen, API-Routen oder Dateinamen ändern, kann das zu fehlerhaften Antworten führen. Lade die Seite deshalb über controllerchange neu oder frage den Nutzer vorher (siehe Beispiel 2).
  • Das zurückgegebene Promise wird sofort erfüllt. Ein await self.skipWaiting() sagt also nichts darüber aus, ob die Aktivierung schon abgeschlossen ist. Code, der den aktiven Zustand braucht, gehört in das activate-Event.
  • skipWaiting() allein übernimmt keine bereits offenen Seiten, die bisher von keinem Worker kontrolliert wurden. Dafür brauchst du zusätzlich clients.claim().
  • Die Methode gibt es nur im Service-Worker-Kontext. In der Seite heißt das Gegenstück registration.waiting.postMessage(...), das eine Nachricht an den wartenden Worker schickt.
  • Service Worker laufen nur in sicheren Kontexten (HTTPS oder localhost). In Firefox sind sie im privaten Modus je nach Version nicht verfügbar.
  • In den DevTools (Chrome: Application → Service Workers) kannst du mit „skipWaiting“ bzw. „Update on reload“ dasselbe Verhalten beim Entwickeln auslösen.