Bidirektionale Kommunikation mit Service Workern

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

In einigen Fällen muss eine Webanwendung einen zweiseitigen Kommunikationskanal zwischen dem und den Service Worker.

Beispiel: In einer Podcast-PWA könnte eine Funktion entwickelt werden, mit der Nutzer Folgen für zur Offlinenutzung und Service Worker, um die Seite regelmäßig über den Fortschritt zu informieren, damit die Hauptseite Thread die UI aktualisieren kann.

In diesem Leitfaden werden die verschiedenen Möglichkeiten zur Implementierung einer wechselseitigen Kommunikation zwischen das Fenster und der Service Worker-Kontext durch Untersuchung verschiedene APIs, die Workbox-Bibliothek sowie einige fortgeschrittene Fälle.

<ph type="x-smartling-placeholder">
</ph> Diagramm mit einem Service Worker und der Seite, die Nachrichten austauschen

Workbox verwenden

workbox-window besteht aus einer Reihe von der Workbox-Bibliothek enthalten, die im Fensterkontext ausgeführt werden soll. Die Workbox bietet eine messageSW()-Methode, um eine Nachricht an den registrierten Service Worker der Instanz zu senden, und auf eine Antwort warten.

Mit dem folgenden Seitencode wird eine neue Workbox-Instanz erstellt und eine Nachricht an den Service Worker gesendet erhalten Sie die Version:

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

const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);

Der Service Worker implementiert am anderen Ende einen Nachrichten-Listener und antwortet dem registrierten Service Worker:

const SW_VERSION = '1.0.0';

self.addEventListener('message', (event) => {
  if (event.data.type === 'GET_VERSION') {
    event.ports[0].postMessage(SW_VERSION);
  }
});

Intern verwendet die Bibliothek eine Browser-API, die im nächsten Abschnitt erläutert wird: Nachricht Kanal, abstrahiert aber viele Implementierungsdetails, was eine einfachere Nutzung ermöglicht und gleichzeitig den umfassenden Browser diese API unterstützt.

Diagramm, das die Zwei-Wege-Kommunikation zwischen Seite und Service Worker unter Verwendung des Workbox-Fensters zeigt.

Browser-APIs verwenden

Wenn die Workbox-Bibliothek für Ihre Anforderungen nicht ausreicht, stehen mehrere untergeordnete APIs zur Verfügung. Implementieren einer wechselseitigen Kommunikation zwischen Seiten und Service Workern. Sie haben einige Ähnlichkeiten und Unterschiede:

Gemeinsamkeiten:

  • In allen Fällen beginnt die Kommunikation an einem Ende über die postMessage()-Schnittstelle und wird empfangen. indem Sie einen message-Handler implementieren.
  • In der Praxis können mit allen verfügbaren APIs dieselben Anwendungsfälle implementiert werden, aber einige davon. die Entwicklung in einigen Szenarien vereinfachen.

Unterschiede:

  • Sie identifizieren die andere Seite der Kommunikation auf unterschiedliche Weise: Einige nutzen ein expliziter Verweis auf den anderen Kontext, während andere implizit über einen Proxy kommunizieren können -Objekt, das auf jeder Seite instanziiert ist.
  • Welche Browser unterstützt werden, hängt von der jeweiligen Situation ab.
Diagramm, das die Zwei-Wege-Kommunikation zwischen Seite und Service Worker und den verfügbaren Browser-APIs zeigt.

Broadcast-Channel-API

Unterstützte Browser

  • Chrome: 54
  • Edge: 79.
  • Firefox: 38.
  • Safari: 15.4

Quelle

Die Broadcast Channel API ermöglicht die grundlegende Kommunikation zwischen Browserkontexten über BroadcastChannel Objekte.

Zur Implementierung muss jeder Kontext zuerst ein BroadcastChannel-Objekt mit derselben ID instanziieren und Nachrichten senden und empfangen:

const broadcast = new BroadcastChannel('channel-123');

Das BroadcastChannel-Objekt stellt eine postMessage()-Schnittstelle bereit, über die eine Nachricht an einen beliebigen Hörer gesendet werden kann. Kontext:

//send message
broadcast.postMessage({ type: 'MSG_ID', });

Jeder Browserkontext kann Nachrichten über die Methode onmessage von BroadcastChannel abhören. -Objekt enthält:

//listen to messages
broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //process message...
  }
};

Es gibt keinen expliziten Verweis auf einen bestimmten Kontext, daher ist keine auf den Service Worker oder einen bestimmten Client verweisen.

Diagramm, das die Zwei-Wege-Kommunikation zwischen der Seite und dem Service Worker mithilfe eines Übertragungskanals zeigt.

Der Nachteil ist, dass die API derzeit Unterstützung von Chrome, Firefox und Edge, aber andere Browser wie Safari unterstützen es nicht. .

Client-API

Unterstützte Browser

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1

Quelle

Mit der Client API können Sie ein Verweis auf alle WindowClient-Objekte für die aktiven Tabs, die der Service Worker steuert

Da die Seite von einem einzelnen Service Worker gesteuert wird, überwacht er den Traffic und sendet Nachrichten an den aktiven Service Worker direkt über die serviceWorker-Schnittstelle:

//send message
navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
});

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

In ähnlicher Weise überwacht der Service Worker Nachrichten, indem er einen onmessage-Listener implementiert:

//listen to messages
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //Process message
  }
});

Für die Rückmeldung mit einem seiner Clients erhält der Service Worker ein Array von WindowClient-Objekten hinzu, indem Sie Folgendes ausführen: Methoden wie Clients.matchAll() und Clients.get() Dann kann es postMessage() einer davon:

//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'});
  }
});
Diagramm, das einen Service Worker zeigt, der mit einem Array von Clients kommuniziert

Client API ist eine gute Option, um einfach mit allen aktiven Tabs eines Service Workers zu kommunizieren relativ einfach erklären. Das API wird von allen wichtigen Browser, Möglicherweise sind jedoch nicht alle Methoden verfügbar. Überprüfen Sie daher die Browserunterstützung, auf Ihrer Website implementieren.

Kanal für Nachrichten

Unterstützte Browser

  • Chrome: 2.
  • Rand: 12.
  • Firefox: 41.
  • Safari: 5.

Quelle

Message Channel erfordert Definition und Übergabe eines Ports von einem Kontext an einen anderen, um eine Zwei-Wege-Kommunikation einzurichten Kanal.

Zum Initialisieren des Channels instanziiert die Seite ein MessageChannel-Objekt und verwendet es , um einen Port an den registrierten Service Worker zu senden. Die Seite implementiert außerdem einen onmessage-Listener auf Nachrichten aus dem anderen Kontext empfangen:

const messageChannel = new MessageChannel();

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

//Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};
Diagramm, das zeigt, wie eine Seite einen Port an einen Service Worker übergibt, um eine Zwei-Wege-Kommunikation einzurichten.

Der Service Worker empfängt den Port, speichert einen Verweis darauf und sendet damit eine Nachricht an den anderen Port Seite:

let communicationPort;

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

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

MessageChannel wird derzeit von allen großen Browser.

Erweiterte APIs: Hintergrundsynchronisierung und Hintergrundabruf

In diesem Leitfaden haben wir Methoden zur Implementierung von Zwei-Wege-Kommunikationstechniken für relativ einfache Fälle wie das Übergeben einer Zeichenfolgennachricht, die den auszuführenden Vorgang beschreibt, oder eine Liste von URLs von einem Kontext in den anderen im Cache zu speichern. In diesem Abschnitt befassen wir uns mit zwei APIs, Mangelnde Internetverbindung und lange Downloads.

Hintergrundsynchronisierung

Unterstützte Browser

  • Chrome: 49.
  • Edge: 79.
  • Firefox: nicht unterstützt
  • Safari: nicht unterstützt.

Quelle

Eine Chat-App möchte möglicherweise sicherstellen, dass Nachrichten nicht aufgrund schlechter Verbindung verloren gehen. Die Mit der Background Sync API können Sie: zu verschieben, wenn der Nutzer eine stabile Verbindung hat. Dies ist nützlich, um sicherzustellen, was der Nutzer senden möchte, tatsächlich gesendet wird.

Anstelle der postMessage()-Schnittstelle registriert die Seite eine sync:

navigator.serviceWorker.ready.then(function (swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});

Der Service Worker wartet dann auf das Ereignis sync, um die Nachricht zu verarbeiten:

self.addEventListener('sync', function (event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

Die Funktion doSomeStuff() sollte ein Versprechen zurückgeben, das den Erfolg/Scheitern der Funktion angibt. was wir tun wollen. Wenn sie erfüllt ist, ist die Synchronisierung abgeschlossen. Wenn er fehlschlägt, wird eine weitere Synchronisierung geplant, noch einmal versuchen. Synchronisierungswiederholungen warten auch auf eine Verbindung und verwenden einen exponentiellen Backoff.

Sobald der Vorgang abgeschlossen ist, kann der Service Worker mit der Seite kommunizieren, um die UI mithilfe einer der zuvor erforschten Kommunikations-APIs aktualisieren.

Die Google-Suche verwendet die Hintergrundsynchronisierung, um fehlgeschlagene Suchanfragen aufgrund einer schlechten Verbindung beizubehalten, und es erneut versuchen. wenn die Nutzenden online sind. Sobald der Vorgang ausgeführt wurde, wird das Ergebnis an über eine Web-Push-Benachrichtigung:

<ph type="x-smartling-placeholder">
</ph> Diagramm, das eine Seite zeigt, die einen Port für eine bidirektionale Kommunikation an einen Service Worker übergibt.

Hintergrundabruf

Unterstützte Browser

  • Chrome: 74
  • Edge: 79.
  • Firefox: nicht unterstützt
  • Safari: wird nicht unterstützt.

Quelle

Bei relativ kurzen Arbeitsschritten wie dem Senden einer Nachricht oder einer Liste von URLs, die im Cache gespeichert werden sollen, sind eine gute Wahl. Wenn die Aufgabe zu lange dauert, beendet der Browser den Dienst Andernfalls stellt dies eine Gefahr für Datenschutz und Akku des Nutzers dar.

Die Background Fetch API ermöglicht es Ihnen, einen Service Worker einer langen Aufgabe zu überlassen, z. B. dem Herunterladen von Filmen, Podcasts oder Levels. eines Spiels.

Wenn Sie von der Seite aus mit dem Service Worker kommunizieren möchten, verwenden Sie backgroundFetch.fetch statt postMessage():

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch(
    'my-fetch',
    ['/ep-5.mp3', 'ep-5-artwork.jpg'],
    {
      title: 'Episode 5: Interesting things.',
      icons: [
        {
          sizes: '300x300',
          src: '/ep-5-icon.png',
          type: 'image/png',
        },
      ],
      downloadTotal: 60 * 1024 * 1024,
    },
  );
});

Mit dem Objekt BackgroundFetchRegistration kann die Seite auf das progress-Ereignis warten, dem folgt Fortschritt des Downloads:

bgFetch.addEventListener('progress', () => {
  // If we didn't provide a total, we can't provide a %.
  if (!bgFetch.downloadTotal) return;

  const percent = Math.round(
    (bgFetch.downloaded / bgFetch.downloadTotal) * 100,
  );
  console.log(`Download progress: ${percent}%`);
});
Diagramm, das zeigt, wie eine Seite einen Port an einen Service Worker übergibt, um eine Zwei-Wege-Kommunikation einzurichten.
Die Benutzeroberfläche wird aktualisiert und zeigt den Fortschritt eines Downloads an (links). Dank der Service Worker kann der Vorgang weiter ausgeführt werden, wenn alle Tabs geschlossen wurden (rechts).

Nächste Schritte

In diesem Leitfaden haben wir uns mit dem allgemeinsten Fall der Kommunikation zwischen Page und Service Workern befasst. (bidirektionale Kommunikation).

Häufig benötigt der eine nur einen Kontext, um mit dem anderen zu kommunizieren, ohne einen Antwort. In den folgenden Leitfäden erfahren Sie, wie Sie unidirektionale Techniken Ihre Seiten vom und zum Service Worker, zusammen mit Anwendungsfällen und Produktionsbeispielen:

  • Leitfaden zum imperativen Caching: Service Worker von der Seite aus aufrufen, im Voraus im Cache speichern (z.B. beim Vorabruf).
  • Broadcast-Updates: Die Seite wird vom Service Worker zur Information aufgerufen. über wichtige Updates (z. B. ist eine neue Version der Web-App verfügbar)