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, den 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.
  • Den Nutzer über eine Änderung der im Cache gespeicherten Daten auf Service Worker-Seite informieren, indem eine Meldung wie „Die App kann jetzt offline verwendet werden“ oder „Neue Version der Inhalte verfügbar“ angezeigt wird.
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 dann ein neuer Service Worker ins Spiel kommt, wird das Banner Update verfügbar angezeigt, damit er die PWA aktualisieren und auf die neuesten Funktionen zugreifen kann:

Screenshot der Webapp-Funktion von Tinder „Update verfügbar“
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, wenn er alle erforderlichen Assets für die Offlinenutzung im Cache gespeichert hat, eine Nachricht an die Seite, um ein Toast-Fenster mit der Meldung „Bereit für die Offlinenutzung“ anzuzeigen, das den Nutzer über die Funktion informiert:

Ein Screenshot der Funktion „Offline verfügbar“ der Squoosh-Web-App
In der Squoosh-PWA sendet der Service Worker ein Update an die Seite, sobald der Cache bereit ist. Auf der Seite wird der Toast „Bereit für die Offline-Arbeit“ 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 erkennen, wann eine neue Version des Service Workers installiert wird, und 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.

Fügen Sie zum Übertragen von Aktualisierungen einen broadcastUpdate.BroadcastUpdatePlugin zu Ihren Strategieoptionen auf der Service-Worker-Seite 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 Service Worker erstellt ein BroadcastChannel-Objekt und sendet Nachrichten an dieses. Jeder Kontext (z. B. eine Seite), der diese Nachrichten empfangen möchte, kann ein BroadcastChannel-Objekt instanziieren und einen Nachrichten-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 erfasst 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.
  }
};

Dies ist eine einfache Methode, aber ihre Einschränkung ist die Browserunterstützung: Zum Zeitpunkt der Veröffentlichung dieses Artikels unterstützt Safari diese API 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 letzten hervorgehobenen 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 eignet sich hervorragend 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 auf diesem Port ein „onmessage“-Handler 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 Dienst-Worker 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 Dienst-Worker delegieren (z. B. einen umfangreichen Download) und die Seite über den Fortschritt informieren.

Zusätzliche Ressourcen