Aktualisierungen an Seiten mit Service Workern senden

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

In einigen Fällen muss der Service Worker proaktiv mit den aktiven Tabs kommunizieren, die er steuert, um über ein bestimmtes Ereignis zu informieren. Beispiele:

  • Die Seite wird informiert, wenn eine neue Version des Service Workers installiert wurde. So kann der Nutzer über die Schaltfläche Aktualisieren, um zu aktualisieren sofort auf die neuen Funktionen zugreifen.
  • Den Nutzer über eine Änderung an zwischengespeicherten Daten informieren, die auf der Service Worker-Seite stattgefunden hat, indem Sie eine Meldung wie „Die App ist jetzt für die Offline-Nutzung bereit“ oder „Neue Version der Inhalte verfügbar“ anzeigen.
Diagramm, das zeigt, wie ein Service Worker mit der Seite kommuniziert, um ein Update zu senden.

Wir bezeichnen diese Arten von Anwendungsfällen, in denen der Service Worker keine Nachricht von der Seite empfangen muss, um eine Kommunikation zu starten, als Broadcast-Updates. In diesem Leitfaden werden verschiedene Möglichkeiten zur Implementierung dieser Art der Kommunikation zwischen Seiten und Service Workern mithilfe von Standardbrowser-APIs und der Workbox-Bibliothek beschrieben.

Produktionsfälle

Tinder

Die Tinder-PWA verwendet workbox-window, um wichtige Momente im Lebenszyklus des Service Workers auf der Seite zu erfassen („installed“, „controlled“ und „activated“). Wenn ein neuer Service Worker zum Einsatz kommt, wird ein Banner mit der Meldung Update verfügbar angezeigt. So können Nutzer die PWA aktualisieren und auf die neuesten Funktionen zugreifen:

Ein Screenshot der Funktion „Update verfügbar“ der Tinder-Web-App.
In der Tinder-PWA teilt der Service Worker der Seite mit, dass eine neue Version verfügbar ist. Die Seite zeigt den Nutzern dann ein Banner mit dem Hinweis „Update verfügbar“ an.

Squoosh

In der Squoosh-PWA wird, wenn der Service Worker alle erforderlichen Assets für die Offline-Nutzung im Cache gespeichert hat, eine Meldung an die Seite gesendet, um einen Hinweis mit dem Text „Bereit für die Offline-Nutzung“ anzuzeigen. So wird der Nutzer über die Funktion informiert:

Ein Screenshot der Squoosh-Web-App mit der Meldung „Ready to work offline“ (Bereit für die Offline-Nutzung).
In der Squoosh-PWA sendet der Service Worker eine Aktualisierung an die Seite, wenn der Cache bereit ist, und auf der Seite wird der Hinweis „Bereit für die Offline-Nutzung“ angezeigt.

Workbox verwenden

Auf Service Worker-Lifecycle-Ereignisse warten

workbox-window bietet eine einfache Schnittstelle zum Abhören wichtiger Service Worker-Lebenszyklusereignisse. Im Hintergrund verwendet die Bibliothek clientseitige APIs wie updatefound und statechange und bietet Event-Listener auf höherer Ebene im workbox-window-Objekt, wodurch die Nutzung dieser Ereignisse für den Nutzer vereinfacht wird.

Mit dem folgenden Seitencode können Sie erkennen, wenn eine neue Version des Service Workers installiert wird, und den Nutzer darüber informieren:

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

Seite über Änderungen an Cache-Daten informieren

Das Workbox-Paket workbox-broadcast-update bietet eine Standardmethode, um Fensterclients darüber zu informieren, dass eine Antwort im Cache aktualisiert wurde. Diese Strategie wird am häufigsten zusammen mit der StaleWhileRevalidate-Strategie verwendet.

Wenn Sie Updates übertragen möchten, fügen Sie den Strategieoptionen im Service Worker-Bereich ein broadcastUpdate.BroadcastUpdatePlugin hinzu:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

In Ihrer Web-App können Sie so auf diese Ereignisse reagieren:

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

Browser-APIs verwenden

Wenn die von Workbox bereitgestellten Funktionen nicht ausreichen, können Sie die folgenden Browser-APIs verwenden, um Broadcast-Updates zu implementieren:

Broadcast Channel API

Der Service Worker erstellt ein BroadcastChannel-Objekt und beginnt, Nachrichten daran zu senden. Jeder Kontext (z.B. eine Seite), der diese Nachrichten empfangen möchte, kann ein BroadcastChannel-Objekt instanziieren und einen Message-Handler implementieren, um Nachrichten zu empfangen.

Verwenden Sie den folgenden Code, um die Seite zu informieren, wenn ein neuer Service Worker installiert wird:

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

Die Seite wartet auf diese Ereignisse, indem sie das sw-update-channel abonniert:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

Das ist eine einfache Technik, aber sie hat eine Einschränkung: die Browserunterstützung. Zum Zeitpunkt der Erstellung dieses Dokuments wird diese API von Safari nicht unterstützt.

Client API

Die Client API bietet eine einfache Möglichkeit, über den Service Worker mit mehreren Clients zu kommunizieren, indem ein Array von Client-Objekten durchlaufen wird.

Verwenden Sie den folgenden Service Worker-Code, um eine Nachricht an den zuletzt fokussierten Tab zu senden:

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

Auf der Seite wird ein Message-Handler implementiert, um diese Nachrichten abzufangen:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

Die Client API ist eine gute Option für Fälle wie das Senden von Informationen an mehrere aktive Tabs. Die API wird von allen gängigen Browsern unterstützt, aber nicht alle ihre Methoden. Prüfen Sie vor der Verwendung, ob Ihr Browser die Funktion unterstützt.

Kanal für Nachrichten

Für Message Channel ist ein anfänglicher Konfigurationsschritt erforderlich, bei dem ein Port von der Seite an den Service Worker übergeben wird, um einen Kommunikationskanal zwischen ihnen einzurichten. Auf der Seite wird ein MessageChannel-Objekt instanziiert und über die postMessage()-Schnittstelle ein Port an den Service Worker übergeben:

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

Die Seite empfängt Nachrichten, indem sie einen „onmessage“-Handler für diesen Port implementiert:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

Der Service Worker empfängt den Port und speichert eine Referenz darauf:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

Ab diesem Zeitpunkt kann es Nachrichten an die Seite senden, indem es postMessage() im Verweis auf den Port aufruft:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel ist möglicherweise komplexer zu implementieren, da Ports initialisiert werden müssen. Es wird jedoch von allen wichtigen Browsern unterstützt.

Nächste Schritte

In diesem Leitfaden haben wir einen bestimmten Fall der Kommunikation zwischen Fenster und Service Worker untersucht: Updates übertragen. Die untersuchten Beispiele umfassen das Abhören wichtiger Service Worker-Lebenszyklusereignisse und die Kommunikation mit der Seite über Änderungen an Inhalten oder im Cache gespeicherten Daten. Es gibt noch viele weitere interessante Anwendungsfälle, in denen der Service Worker proaktiv mit der Seite kommuniziert, ohne zuvor eine Nachricht erhalten zu haben.

Weitere Muster für die Kommunikation zwischen Fenstern und Service Workern finden Sie unter:

  • Imperative Caching Guide: Aufrufen eines Service Workers von der Seite, um Ressourcen im Voraus zu speichern (z.B. in Prefetching-Szenarien).
  • Zwei-Wege-Kommunikation: Eine Aufgabe an einen Service Worker delegieren (z.B. einen umfangreichen Download) und die Seite über den Fortschritt auf dem Laufenden halten.

Zusätzliche Ressourcen