Aktualisierungen an Seiten mit Service Workern senden

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

In einigen Szenarien muss der Service Worker möglicherweise proaktiv mit einem der aktiven Tabs kommunizieren, die er steuert, um Informationen zu einem bestimmten Ereignis zu senden. Beispiele:

  • Die Seite wird informiert, wenn eine neue Version des Service Workers installiert wurde, sodass auf der Seite dem Nutzer die Schaltfläche Aktualisieren zum Aktualisieren angezeigt werden kann, um sofort auf die neue Funktion zuzugreifen.
  • Sie informieren den Nutzer mit einem Hinweis wie Die App kann jetzt offline ausgeführt werden oder Neue Version der Inhalte verfügbar über eine Änderung an den im Cache gespeicherten Daten, die beim Service Worker vorgenommen wurde.
Diagramm, das zeigt, wie ein Service Worker mit der Seite kommuniziert, um eine Aktualisierung zu senden.

Wir nennen diese Art von Anwendungsfällen, bei denen der Service Worker keine Nachricht von der Seite erhalten muss, um eine Kommunikation zu starten, "Broadcast-Updates". In diesem Leitfaden werden verschiedene Möglichkeiten zur Implementierung dieser Art der Kommunikation zwischen Seiten und Service Workern mithilfe von standardmäßigen Browser-APIs und der Workbox-Bibliothek beschrieben.

Produktionsfälle

Tinder

Tinder PWA verwendet workbox-window, um wichtige Momente im Service Worker-Lebenszyklus auf der Seite zu erfassen („installiert“, „gesteuert“ und „aktiviert“). Wenn ein neuer Service Worker hinzukommt, wird das Banner Update verfügbar angezeigt, sodass er die PWA aktualisieren und auf die neuesten Funktionen zugreifen kann:

Screenshot der Web-App-Funktion „Update verfügbar“ von Tinder.
In der Tinder-PWA teilt der Service Worker der Seite mit, dass eine neue Version verfügbar ist, und auf der Seite wird das Banner „Update verfügbar“ angezeigt.

Squoosh

Wenn der Service Worker in der Squoosh-PWA alle erforderlichen Assets im Cache gespeichert hat, damit sie offline verwendet werden können, sendet er eine Nachricht an die Seite mit einem Toast mit dem Hinweis „Bereit zur Offlinenutzung“, um den Nutzer über die Funktion zu informieren:

Screenshot der Funktion „Bereit zur Offlinenutzung“ in der Squoosh-Webanwendung.
In der Squoosh-PWA sendet der Service Worker ein Update für die Seite, wenn der Cache bereit ist. Auf der Seite wird der Toast „Bereit zur Offlinenutzung“ angezeigt.

Workbox verwenden

Service Worker-Lebenszyklusereignisse überwachen

workbox-window bietet eine einfache Schnittstelle, über die Sie wichtige Service Worker-Lebenszyklusereignisse überwachen können. Intern verwendet die Bibliothek clientseitige APIs wie updatefound und statechange und bietet Ereignis-Listener auf höherer Ebene im workbox-window-Objekt, sodass der Nutzer diese Ereignisse leichter nutzen kann.

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

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

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

wb.register();

Die Seite über Änderungen der Cache-Daten informieren

Das Workbox-Paket workbox-broadcast-update bietet eine Standardmethode, um Fenster-Clients darüber zu informieren, dass eine im Cache gespeicherte Antwort aktualisiert wurde. Dies wird am häufigsten in Verbindung mit der StalewhileRevalid-Strategie verwendet.

Fügen Sie Ihren Strategieoptionen auf der Service Worker-Seite ein broadcastUpdate.BroadcastUpdatePlugin hinzu, um Aktualisierungen zu übertragen:

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 auf folgende Ereignisse warten:

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 bereitgestellte Funktionalität für Ihre Anforderungen nicht ausreicht, verwenden Sie die folgenden Browser-APIs, um Broadcast-Updates zu implementieren:

Broadcast-Channel-API

Der Service Worker erstellt ein BroadcastChannel-Objekt und beginnt mit dem Senden von Nachrichten. 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 über die Installation eines neuen Service Workers zu informieren:

// 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.
  }
};

Dies ist eine einfache Methode, aber ihre Einschränkung ist die Browserunterstützung: Zum jetzigen Zeitpunkt wird diese API von Safari nicht unterstützt.

Client-API

Die Client API bietet eine einfache Möglichkeit, mit mehreren Clients vom Service Worker zu kommunizieren. Sie führt die Iteration über ein Array von Client-Objekten durch.

Mit dem folgenden Service Worker-Code senden Sie eine Nachricht an den letzten fokussierten Tab:

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

Die Seite implementiert einen Nachrichten-Handler, der diese Nachrichten abfängt:

// 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 die Übertragung von Informationen auf mehrere aktive Tabs. Die API wird von allen gängigen Browsern unterstützt, aber nicht von allen Methoden. Überprüfen Sie die Browserunterstützung, bevor Sie es verwenden.

Kanal für Nachrichten

Der Nachrichtenkanal erfordert einen ersten Konfigurationsschritt. Dabei wird ein Port von der Seite an den Service Worker übergeben, um einen Kommunikationskanal zwischen ihnen einzurichten. 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 hört Nachrichten ab, indem sie einen „onmessage“-Handler an diesem Port implementiert:

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

Der Service Worker empfängt den Port und speichert einen Verweis darauf:

// Initialize
let communicationPort;

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

Von diesem Punkt können Nachrichten an die Seite gesendet werden, indem postMessage() im Verweis auf den Port aufgerufen wird:

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

Die Implementierung von MessageChannel ist möglicherweise aufgrund der erforderlichen Initialisierung von Ports komplexer, wird aber von allen gängigen Browsern unterstützt.

Nächste Schritte

In diesem Leitfaden wurde ein bestimmter Fall der Kommunikation zwischen Windows und Service Workern betrachtet: "broadcast updates". Zu den untersuchten Beispielen gehört das Warten auf wichtige Service-Worker-Lebenszyklus-Ereignisse und die Kommunikation mit der Seite über Änderungen an Inhalten oder im Cache gespeicherten Daten. Es gibt noch interessantere Anwendungsfälle, bei denen der Service Worker proaktiv mit der Seite kommuniziert, ohne vorher eine Nachricht zu erhalten.

Weitere Kommunikationsmuster für Fenster und Service Worker finden Sie hier:

  • Leitfaden für Imperatives Caching: Aufrufen eines Service Workers von der Seite aus, um Ressourcen im Voraus im Cache zu speichern (z.B. in Prefetch-Szenarien).
  • Zwei-Wege-Kommunikation: Delegieren einer Aufgabe an einen Service Worker, z.B. bei einem umfangreichen Download, und Informieren der Seite über den Fortschritt.

Zusätzliche Ressourcen