Service Worker-Mentalität

Denken Sie im Hinblick auf Service Workers

Service Worker sind leistungsstark und es lohnt sich, es zu lernen. Sie ermöglichen es Ihnen, Ihren Nutzern eine völlig neue Erfahrung zu bieten. Ihre Website kann sofort geladen werden. Es kann offline ausgeführt werden. Er kann als plattformspezifische App installiert werden und wirkt so ausgefeilt, aber mit der Reichweite und Freiheit des Webs.

Service Worker sind jedoch anders als alles, was die meisten von uns Webentwicklern gewohnt sind. Sie bringen eine steile Lernkurve mit sich und es gibt ein paar Tricks, auf die du achten solltest.

Google Developers und ich haben vor Kurzem an einem Projekt Service Workies zusammengearbeitet. Das ist ein kostenloses Spiel, mit dem sich Service Worker besser verstehen lassen. Bei der Entwicklung und der Arbeit mit den komplexen Details der Service Worker stieß ich auf ein paar Probleme. Was mir am meisten geholfen hat, war, einige bildliche Metaphern zu finden. In diesem Beitrag beschäftigen wir uns mit diesen mentalen Modellen und beschäftigen uns mit den paradoxen Eigenschaften, die Servicearbeiter sowohl knifflig als auch genial machen.

Gleich, aber unterschiedlich

Beim Programmieren Ihres Service Workers werden Ihnen viele Dinge vertraut vorkommen. Sie können Ihre bevorzugten neuen JavaScript-Sprachfunktionen verwenden. Lebenszyklus-Ereignisse werden genauso überwacht wie UI-Ereignisse. Du steuerst den Ablauf mit Versprechen, wie du es gewohnt bist.

Anderes Verhalten von Service Workern führt jedoch dazu, dass Sie sich verwirrt fühlen. Das gilt besonders, wenn du die Seite aktualisierst und die Änderungen am Code nicht angezeigt werden.

Neue Ebene

Normalerweise müssen Sie beim Erstellen einer Website nur zwei Ebenen berücksichtigen: den Client und den Server. Der Service Worker ist ein brandneuer Layer in der Mitte.

Ein Service Worker fungiert als mittlere Ebene zwischen Client und Server

Stellen Sie sich Ihren Service Worker als eine Art Browsererweiterung vor, also eine Erweiterung, die Ihre Website in den Browsern der Nutzer installieren kann. Nach der Installation extends der Service Worker den Browser für Ihre Website um eine leistungsstarke mittlere Ebene. Diese Service Worker-Ebene kann alle Anfragen Ihrer Website abfangen und verarbeiten.

Die Service Worker-Ebene hat einen eigenen Lebenszyklus, der unabhängig vom Browsertab ist. Eine einfache Seitenaktualisierung allein reicht nicht aus, um einen Service Worker zu aktualisieren. So wie Sie es auch nicht erwarten würden, dass eine Seitenaktualisierung den auf einem Server bereitgestellten Code aktualisiert. Jede Ebene hat ihre eigenen eindeutigen Regeln für die Aktualisierung.

Im Spiel Service Workies befassen wir uns mit vielen Details des Service Worker-Lebenszyklus und geben Ihnen eine Menge Übungen dazu.

Leistungsstark, aber begrenzt

Ein Service Worker an Ihrem Standort hat für Sie unglaubliche Vorteile. Ihre Website kann:

  • einwandfrei funktionieren, auch wenn der Nutzer offline ist.
  • Erhebliche Leistungsverbesserungen durch Caching
  • Push-Benachrichtigungen verwenden
  • als PWA installiert werden müssen,

So viel Service Worker können tun, sind sie durch ihr Design eingeschränkt. Sie können nichts synchron oder im selben Thread wie Ihre Website tun. Das bedeutet, dass Sie keinen Zugriff mehr auf:

  • localStorage
  • das DOM
  • das Fenster

Die gute Nachricht: Es gibt verschiedene Möglichkeiten, wie Ihre Seite mit dem Service Worker kommunizieren kann, darunter direkte postMessage, 1:1-Nachrichtenkanäle und 1:n-Broadcast-Kanäle.

Langlebig, aber kurzlebig

Ein aktiver Service Worker lebt auch dann weiter, wenn ein Nutzer Ihre Website verlässt oder den Tab schließt. Der Browser behält diesen Service Worker bei, sodass er beim nächsten Besuch deiner Website durch den Nutzer einsatzbereit ist. Bevor die erste Anfrage gestellt wird, kann der Service Worker diese abfangen und die Kontrolle über die Seite übernehmen. Dies ermöglicht es einer Website, offline zu arbeiten. Der Service Worker kann eine im Cache gespeicherte Version der Seite selbst bereitstellen, auch wenn der Nutzer keine Verbindung zum Internet hat.

In Service Workies visualisieren wir dieses Konzept, bei dem Kolohe, ein freundlicher Service Worker, Anfragen abfängt und verarbeitet.

Beendet

Auch wenn Service Worker so scheinen, dass sie unsterblich sind, können sie nahezu jederzeit beendet werden. Der Browser möchte keine Ressourcen für einen Service Worker verschwenden, der gerade nichts tut. Ein Beenden zu beenden ist nicht das Gleiche wie das Beenden der Anwendung. Der Service Worker bleibt installiert und aktiviert. Er wurde einfach eingeschlafen. Wenn er das nächste Mal benötigt wird (z.B. um eine Anfrage zu verarbeiten), wird er vom Browser wieder aktiviert.

waitUntil

Die ständige Möglichkeit, in den Ruhemodus zu verschlafen, ist eine Möglichkeit, dem Browser mitzuteilen, dass er eine wichtige Aktion durchgeführt hat und keine Nickerchen machen möchte. Hier kommt event.waitUntil() ins Spiel. Diese Methode verlängert den Lebenszyklus, in dem sie verwendet wird, und verhindert so, dass sie gestoppt wird und in die nächste Lebenszyklusphase übergeht, bis wir bereit sind. So haben wir Zeit, Caches einzurichten, Ressourcen aus dem Netzwerk abzurufen usw.

In diesem Beispiel wird dem Browser mitgeteilt, dass die Installation des Service Workers erst abgeschlossen ist, wenn der Cache assets erstellt und das Bild eines Schwerts eingefügt wurde:

self.addEventListener("install", event => {
  event.waitUntil(
    caches.open("assets").then(cache => {
      return cache.addAll(["/weapons/sword/blade.png"]);
    })
  );
});

Auf globaler Ebene achten

In diesem Fall wird der globale Bereich des Service Workers zurückgesetzt. Achten Sie also darauf, keinen globalen Status in Ihrem Service Worker zu verwenden, da Sie sonst traurig sind, wenn er das nächste Mal wieder aufwacht und einen anderen Status als erwartet hat.

In diesem Beispiel wird ein globaler Status verwendet:

const favoriteNumber = Math.random();
let hasHandledARequest = false;

self.addEventListener("fetch", event => {
  console.log(favoriteNumber);
  console.log(hasHandledARequest);
  hasHandledARequest = true;
});

Dieser Service Worker protokolliert bei jeder Anfrage eine Nummer, z. B. 0.13981866382421893. Die Variable hasHandledARequest ändert sich ebenfalls in true. Der Service Worker ist nun für eine Weile inaktiv, daher wird er vom Browser angehalten. Bei der nächsten Anfrage wird der Service Worker wieder benötigt, sodass der Browser ihn aktiviert. Das Skript wird noch einmal bewertet. Jetzt wurde hasHandledARequest auf false zurückgesetzt und favoriteNumber ist etwas ganz anderes: 0.5907281835659033.

Sie können sich nicht auf den gespeicherten Status in einem Service Worker verlassen. Auch das Erstellen von Instanzen von Elementen wie Nachrichtenkanälen kann zu Fehlern führen: Sie erhalten bei jedem Anhalten/Starten des Service Workers eine brandneue Instanz.

In Kapitel 3 der Service Workies sehen wir, wie unser angehaltener Service Worker seine Farbe verliert, während er aufwacht.

Visualisierung eines angehaltenen Service Workers

Zusammen, aber getrennt

Ihre Seite kann jeweils nur von einem Service Worker gesteuert werden. Es können aber zwei Service Worker gleichzeitig installiert sein. Wenn Sie den Service Worker-Code ändern und die Seite aktualisieren, bearbeiten Sie den Service Worker gar nicht. Service Worker sind unveränderlich. Sie erstellen stattdessen ein ganz neues. Dieser neue Service Worker (auch SW2 genannt) installiert, wird jedoch noch nicht aktiviert. Sie muss warten, bis der aktuelle Service Worker (SW1) beendet wird (wenn der Nutzer Ihre Website verlässt).

Probleme mit den Caches eines anderen Service Worker beheben

Während der Installation kann SW2 Einstellungen vornehmen und normalerweise Caches erstellen und füllen. Aber Vorsicht: Dieser neue Service Worker hat Zugriff auf alle Inhalte, auf die der aktuelle Service Worker Zugriff hat. Wenn Sie nicht aufpassen, kann der neue wartende Service Worker wirklich durcheinanderbringen. Einige Beispiele, die Probleme verursachen können:

  • SW2 könnte einen Cache löschen, den SW1 aktiv nutzt.
  • SW2 könnte den Inhalt eines von SW1 verwendeten Cache bearbeiten, was dazu führt, dass SW1 mit Inhalten antwortet, die von der Seite nicht erwartet werden.

Überspringen überspringen

Ein Service Worker kann auch die riskante Methode skipWaiting() verwenden, um die Kontrolle über die Seite zu übernehmen, sobald die Installation abgeschlossen ist. Das ist im Allgemeinen keine gute Idee, es sei denn, Sie möchten absichtlich einen fehlerhaften Servicemitarbeiter ersetzen. Der neue Service Worker verwendet möglicherweise aktualisierte Ressourcen, die von der aktuellen Seite nicht erwartet werden, was zu Fehlern und Programmfehlern führt.

Reinigen

Wenn Sie verhindern möchten, dass Ihre Service Worker sich gegenseitig überschreiben, können Sie verschiedene Caches verwenden. Am einfachsten ist es, die von ihnen verwendeten Cache-Namen zu versionieren.

const version = 1;
const assetCacheName = `assets-${version}`;

self.addEventListener("install", event => {
  caches.open(assetCacheName).then(cache => {
    // confidently do stuff with your very own cache
  });
});

Wenn Sie einen neuen Service Worker bereitstellen, erweitern Sie den version, sodass er mit einem vollständig vom vorherigen Service Worker getrennten Cache alles tut, was er braucht.

Visualisierung eines Cache

Bereinigung beenden

Sobald Ihr Service Worker den Status activated erreicht hat, wissen Sie, dass er übernommen hat und der vorherige Service Worker redundant ist. An dieser Stelle ist es wichtig, nach dem alten Service Worker eine Bereinigung durchzuführen. Dabei werden nicht nur die Cache-Speicherlimits Ihrer Nutzer berücksichtigt, sondern auch unbeabsichtigte Fehler verhindert.

Die Methode caches.match() ist eine häufig verwendete Tastenkombination zum Abrufen eines Elements aus allen Caches, bei denen eine Übereinstimmung vorliegt. Die Caches werden jedoch in der Reihenfolge durchlaufen, in der sie erstellt wurden. Sie haben zwei Versionen der Skriptdatei app.js in zwei verschiedenen Caches: assets-1 und assets-2. Für deine Seite wird das neuere Skript erwartet, das in assets-2 gespeichert ist. Wenn du den alten Cache jedoch nicht gelöscht hast, gibt caches.match('app.js') den alten Cache von assets-1 zurück. Wahrscheinlich funktioniert dann deine Website nicht mehr.

Zum Bereinigen nach vorherigen Service Workern müssen Sie lediglich den Cache löschen, den der neue Service Worker nicht benötigt:

const version = 2;
const assetCacheName = `assets-${version}`;

self.addEventListener("activate", event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== assetCacheName){
            return caches.delete(cacheName);
          }
        });
      );
    });
  );
});

Sich gegenseitig zu verhindern, ist aufwendig und diszipliniert. Der Aufwand ist aber lohnenswert.

Service Worker-Mentalität

Wenn Sie mit der richtigen Denkweise über Service Worker nachdenken, können Sie Ihre Arbeit mit Selbstvertrauen aufbauen. Sobald Sie sich mit ihnen vertraut gemacht haben, können Sie unglaubliche Erfahrungen für Ihre Nutzer schaffen.

Wenn Sie all dies verstehen möchten, indem Sie ein Spiel spielen, dann haben Sie Glück. Spiele Service Workies. Dort lernst du, wie ein Service Worker die Offline-Schädlinge besiegen kann.