Aktualisierungen an Seiten mit Service Workern senden

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

In einigen Fällen muss der Dienst-Worker möglicherweise proaktiv mit einem der aktiven Tabs kommunizieren, die er steuert, um über ein bestimmtes Ereignis zu informieren. Beispiele:

  • Die Seite wird darüber informiert, wenn eine neue Version des Service Workers installiert wurde, damit die Seite dem Nutzer die Schaltfläche Aktualisieren, um zu aktualisieren anzeigen kann, um sofort auf die neuen Funktionen zuzugreifen.
  • Informieren Sie den Nutzer über eine Änderung an den im Cache gespeicherten Daten, die auf der Service Worker-Seite stattgefunden hat. Zeigen Sie dazu eine Meldung wie „Die App kann jetzt offline verwendet werden“ oder „Neue Version der Inhalte verfügbar“ an.
Diagramm, das einen Service Worker zeigt, der mit der Seite kommuniziert, um ein Update zu senden

Diese Anwendungsfälle, bei denen der Service Worker keine Nachricht von der Seite erhalten muss, um eine Kommunikation zu starten, werden als „Broadcast-Aktualisierungen“ bezeichnet. In diesem Leitfaden werden verschiedene Möglichkeiten zur Implementierung dieser Art der Kommunikation zwischen Seiten und Service Workern mithilfe von Standard-Browser-APIs und der Workbox-Bibliothek beschrieben.

Produktionsfälle

Tinder

Die Tinder-PWA verwendet workbox-window, um wichtige Lebenszyklusmomente von Service Workern auf der Seite zu überwachen („installiert“, „kontrolliert“ und „aktiviert“). Wenn also ein neuer Dienst-Worker ins Spiel kommt, wird ein Banner mit der Meldung Update verfügbar angezeigt, damit Nutzer die PWA aktualisieren und auf die neuesten Funktionen zugreifen können:

Ein Screenshot der Funktion „Update verfügbar“ in der Tinder-Web-App.
In der Tinder-PWA teilt der Service Worker der Seite mit, dass eine neue Version verfügbar ist. Daraufhin wird den Nutzern auf der Seite ein Banner mit der Meldung „Update verfügbar“ angezeigt.

Squoosh

In der Squoosh-PWA sendet der Dienst-Worker eine Nachricht an die Seite, wenn er alle erforderlichen Assets im Cache gespeichert hat, damit die Anwendung offline funktioniert. Daraufhin wird eine Toast-Mitteilung mit dem Text „Bereit für die Offlinenutzung“ angezeigt, um den Nutzer über die Funktion zu informieren:

Ein Screenshot der Funktion „Offline verfügbar“ der Squoosh-Web-App
In der Squoosh-PWA sendet der Service Worker eine Aktualisierung an die Seite, wenn der Cache bereit ist. Auf der Seite wird dann die Meldung „Offline verfügbar“ angezeigt.

Workbox verwenden

Auf Service Worker-Lifecycle-Ereignisse warten

workbox-window bietet eine einfache Schnittstelle, um wichtige Lebenszyklusereignisse von Dienstmitarbeitern zu überwachen. Im Hintergrund verwendet die Bibliothek clientseitige APIs wie updatefound und statechange und bietet Ereignislistener auf höherer Ebene im workbox-window-Objekt, was die Nutzung dieser Ereignisse für den Nutzer erleichtert.

Mit dem folgenden Seitencode können Sie jedes Mal erkennen, wenn eine neue Version des Dienst-Workers installiert wird, und dies dem Nutzer mitteilen:

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 Window-Clients darüber zu informieren, dass eine im Cache gespeicherte Antwort aktualisiert wurde. Dieser wird am häufigsten zusammen mit der Strategie StaleWhileRevalidate verwendet.

Wenn Sie Aktualisierungen übertragen möchten, fügen Sie Ihren Strategieoptionen auf der Service Worker-Seite 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 Webanwendung können Sie diese Ereignisse so beobachten:

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-Aktualisierungen“ zu implementieren:

Broadcast Channel API

Der Dienst-Worker erstellt ein BroadcastChannel-Objekt und sendet Nachrichten an dieses Objekt. 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 darüber zu informieren, dass ein neuer Dienst-Worker installiert wurde:

// 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 überwacht diese Ereignisse, indem sie 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 Methode, die jedoch durch die Browserunterstützung eingeschränkt ist: Safari unterstützt diese API derzeit nicht.

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 Nachrichten-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 die Übertragung von Informationen an mehrere aktive Tabs. Die API wird von allen gängigen Browsern unterstützt, aber nicht alle Methoden. Prüfen Sie vor der Verwendung, ob Ihr Browser unterstützt wird.

Kanal für Nachrichten

Für den Nachrichtenkanal ist ein erster Konfigurationsschritt erforderlich, bei dem ein Port von der Seite an den Service Worker übergeben wird, um einen Kommunikationskanal zwischen ihnen herzustellen. Die Seite instanziiert ein MessageChannel-Objekt und übergibt über die postMessage()-Schnittstelle einen Port an den Service Worker:

const messageChannel = new MessageChannel();

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

Die Seite überwacht Nachrichten, indem ein „onmessage“-Handler auf diesem Port implementiert wird:

// 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];
  }
});

Von diesem Punkt aus kann es Nachrichten an die Seite senden, indem es postMessage() in der Referenz zum Port aufruft:

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

MessageChannel ist aufgrund der Notwendigkeit, Ports zu initialisieren, möglicherweise komplexer zu implementieren, wird aber von allen gängigen Browsern unterstützt.

Nächste Schritte

In diesem Leitfaden haben wir einen bestimmten Fall der Kommunikation zwischen Fenster und Dienstanbieter untersucht: „Broadcast-Aktualisierungen“. Zu den Beispielen gehören das Abhören wichtiger Lebenszyklusereignisse von Service Workern und die Kommunikation von Änderungen an Inhalten oder im Cache an die Seite. Es gibt noch interessantere 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 Fenster und Dienstworkern finden Sie hier:

  • Imperatives Caching: Ein Service Worker wird von der Seite aufgerufen, um Ressourcen im Voraus im Cache zu speichern (z.B. in Prefetching-Szenarien).
  • Zwei-Wege-Kommunikation: Sie können eine Aufgabe an einen Service Worker delegieren (z.B. einen umfangreichen Download) und die Seite über den Fortschritt informieren.

Zusätzliche Ressourcen