Service Worker-Mentalität

Service Worker:innen denken

Service Worker sind leistungsstark und es lohnt sich, zu lernen. Sie ermöglichen eine völlig neue Nutzererfahrung. Ihre Website kann sofort geladen werden. Sie kann offline verwendet werden. Die App lässt sich als plattformspezifische App installieren und wirkt dadurch noch ein bisschen ausgereift – aber mit der Reichweite und Freiheit des Webs.

Service Worker sind jedoch anders als alles, was die meisten von uns Web-Entwickler gewohnt sind. Sie sind mit einer steilen Lernkurve verbunden und es gibt ein paar Probleme, auf die du achten musst.

Google Developers und ich haben vor Kurzem an einem Projekt mit dem Namen Service Workies zusammengearbeitet. Mit diesem kostenlosen Spiel möchten wir Service Worker besser verstehen. Bei der Konstruktion und der Arbeit mit den komplexen Besonderheiten der Service-Worker bin ich auf ein paar Probleme gestoßen. Am meisten hat mir geholfen, sich ein paar bildliche Metaphern auszudenken. In diesem Beitrag beschäftigen wir uns mit diesen mentalen Modellen und beschäftigen uns mit den paradoxen Eigenschaften, die Service Worker sowohl knifflig als auch großartig machen.

Gleich, aber anders

Während der Programmierung Ihres Service Workers werden Ihnen viele Dinge vertraut vorkommen. Sie können Ihre bevorzugten neuen JavaScript-Sprachfunktionen verwenden. Lebenszyklusereignisse werden genau wie UI-Ereignisse überwacht. Du steuerst den Ablauf mit Promise wie du es gewohnt bist.

Andere Verhaltensweisen der Mitarbeiter führen jedoch zu Verwirrung. vor allem, wenn du die Seite aktualisierst und deine Codeänderungen nicht übernommen 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 eine brandneue Schicht, die sich in der Mitte befindet.

Ein Service Worker fungiert als Mittelschicht zwischen dem Client und dem Server

Stellen Sie sich Ihren Service Worker als eine Art Browsererweiterung vor, die Ihre Website im Browser Ihrer Nutzer installieren kann. Nach der Installation erweitert 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 ihren eigenen Lebenszyklus, der vom Browsertab unabhängig ist. Eine einfache Seitenaktualisierung reicht nicht aus, um einen Service Worker zu aktualisieren. Ebenso würden Sie nicht erwarten, dass bei einer Seitenaktualisierung der auf einem Server bereitgestellte Code aktualisiert wird. Jede Ebene hat eigene, eindeutige Regeln für die Aktualisierung.

Im Spiel Service Worker geht es um viele Details des Lebenszyklus von Service Workern und Sie haben jede Menge Übung im Umgang damit.

Leistungsstark, aber mit Einschränkungen

Ein Service Worker auf Ihrer Website bietet Ihnen enorme Vorteile. Ihre Website kann:

  • einwandfrei funktionieren, auch wenn der Nutzer offline ist
  • erhebliche Leistungsverbesserungen durch Caching
  • Push-Benachrichtigungen verwenden
  • Installation als PWA

Service Worker können nicht mehr so viel tun, sind aber designbedingt begrenzt. Sie können keine Aktionen ausführen, die synchron oder im selben Thread wie Ihre Website sind. Sie haben also keinen Zugriff auf Folgendes:

  • localStorage
  • DOM
  • das Fenster

Die gute Nachricht ist, dass es einige Möglichkeiten gibt, wie Ihre Seite mit dem Service Worker kommunizieren kann, z. B. postMessage, 1:1-Nachrichtenkanäle und 1:n-Broadcast-Kanäle.

Langlebig, aber kurzlebig

Ein aktiver Service Worker bleibt weiter, auch wenn ein Nutzer Ihre Website verlässt oder den Tab schließt. Der Browser behält diesen Service Worker bei, damit er bereit ist, wenn der Nutzer das nächste Mal auf Ihre Website zurückkehrt. Vor der allerersten Anfrage erhält der Service Worker die Möglichkeit, die Seite abzufangen und die Kontrolle über die Seite zu übernehmen. Dadurch kann eine Website offline ausgeführt werden. Der Service Worker kann eine im Cache gespeicherte Version der Seite selbst bereitstellen, selbst wenn der Nutzer keine Verbindung zum Internet hat.

In Service Workies wird dieses Konzept veranschaulicht, wie ein freundlicher Service Worker Kolohe Anfragen abfängt und verarbeitet.

Angehalten

Service Worker scheinen unsterblich zu sein, können aber jederzeit eingestellt werden. Der Browser möchte keine Ressourcen an einen Service Worker verschwenden, der gerade nichts tut. Stoppen ist nicht dasselbe wie beendet – der Service Worker bleibt installiert und aktiviert. Er wurde einfach in den Ruhemodus versetzt. Wenn sie das nächste Mal benötigt wird, z.B. um eine Anfrage zu verarbeiten, wird sie vom Browser wieder aktiviert.

waitUntil

Da es ständig möglich ist, in den Ruhemodus zu wechseln, benötigt Ihr Service Worker eine Möglichkeit, den Browser zu informieren, wenn er etwas Wichtiges tut und nicht das Gefühl hat, ein Nickerchen zu machen. Hier kommt event.waitUntil() ins Spiel. Diese Methode erweitert den Lebenszyklus, in dem sie verwendet wird, sodass sie nicht beendet wird, sondern auch erst dann in die nächste Phase des Lebenszyklus übergeht, bis sie bereit ist. Dadurch haben wir Zeit, Caches einzurichten, Ressourcen aus dem Netzwerk abzurufen usw.

Dieses Beispiel teilt dem Browser mit, dass der Service Worker die Installation erst abgeschlossen hat, wenn der assets-Cache erstellt und mit dem Bild eines Schwerts gefüllt wurde:

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

Auf globalen Zustand achten

Durch dieses Starten/Stoppen wird der globale Geltungsbereich des Service Workers zurückgesetzt. Achten Sie also darauf, in Ihrem Service Worker keinen globalen Status zu verwenden, da Sie sonst traurig wären, wenn er das nächste Mal aufwacht und einen anderen Status hat als erwartet.

Betrachten Sie dieses Beispiel mit einem globalen Status:

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. Jetzt ist der Service Worker eine Weile inaktiv, daher beendet der Browser ihn. Bei der nächsten Anfrage wird der Service Worker wieder benötigt, sodass er vom Browser aktiviert wird. Das Skript wird noch einmal ausgewertet. Jetzt wird 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. Das Erstellen von Instanzen von Dingen wie Nachrichtenkanälen kann außerdem zu Fehlern führen: Sie erhalten bei jedem Anhalten/Starten des Service Workers eine ganz neue Instanz.

In Kapitel 3 der Service-Workies stellen wir fest, dass ein angehaltener Service Worker seine Farbe verliert, während er auf das Aufwachen wartet.

Visualisierung eines beendeten Service Workers

Zusammen, aber getrennt

Ihre Seite kann jeweils nur von einem Service Worker gesteuert werden. Es können jedoch zwei Service Worker gleichzeitig installiert sein. Wenn Sie den Code Ihres Service Workers ändern und die Seite aktualisieren, wird der Service Worker nicht tatsächlich bearbeitet. Service Worker sind unveränderlich. Stattdessen erstellen Sie ein ganz neues. Dieser neue Service Worker (wir nennen ihn SW2) wird installiert, aber noch nicht aktiviert. Er muss warten, bis der aktuelle Service Worker (SW1) beendet wird, also wenn der Nutzer Ihre Website verlässt.

Fehler in den Caches eines anderen Service Workers beheben

Während der Installation kann SW2 die Konfiguration vornehmen und in der Regel Caches erstellen und füllen. Beachten Sie jedoch, dass dieser neue Service Worker Zugriff auf alle Daten hat, auf die der aktuelle Service Worker Zugriff hat. Wenn Sie nicht aufpassen, kann Ihr neuer Service Worker Ihrem aktuellen Service Worker wirklich etwas Unordnung bringen. Hier einige Beispiele für mögliche Probleme:

  • SW2 könnte einen Cache löschen, den SW1 aktiv verwendet.
  • SW2 könnte den Inhalt des von SW1 verwendeten Caches bearbeiten, sodass SW1 mit Assets antwortet, die die Seite nicht erwartet.

ÜberspringenSkipWarten

Ein Service Worker kann auch die riskante skipWaiting()-Methode verwenden, um direkt nach der Installation die Kontrolle über die Seite zu übernehmen. Das ist in der Regel keine gute Idee, es sei denn, Sie versuchen absichtlich, einen fehlerhaften Service Worker zu ersetzen. Der neue Service Worker verwendet möglicherweise aktualisierte Ressourcen, die von der aktuellen Seite nicht erwartet werden, was zu Fehlern und Bugs führt.

Bereinigung starten

Um zu verhindern, dass sich Ihre Service Worker gegenseitig überschreiben, müssen Sie dafür sorgen, dass sie unterschiedliche Caches verwenden. Am einfachsten geht dies, indem Sie die verwendeten Cache-Namen 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, übertragen Sie den version so, dass er das tut, was er braucht – mit einem vollständig vom vorherigen Service Worker getrennten Cache.

Visualisierung eines Cache

Bereinigung beenden

Sobald Ihr Service Worker den Status activated erreicht, wissen Sie, dass er übernommen wurde und der vorherige Service Worker redundant ist. An dieser Stelle ist es wichtig, die Bereinigung nach dem alten Service Worker durchzuführen. Sie respektiert nicht nur die im Cache gespeichert werden, aber unbeabsichtigte Fehler vermeiden.

Die Methode caches.match() ist ein häufig verwendetes Kürzel zum Abrufen eines Elements aus einem beliebigen Cache, bei dem eine Übereinstimmung vorliegt. Die Caches werden jedoch in der Reihenfolge durchlaufen, in der sie erstellt wurden. Angenommen, Sie haben zwei Versionen einer Skriptdatei app.js in zwei verschiedenen Caches: assets-1 und assets-2. Deine Seite erwartet das neuere Skript, das in assets-2 gespeichert ist. Wenn du den alten Cache allerdings nicht gelöscht hast, gibt caches.match('app.js') den alten von assets-1 zurück, wodurch deine Website höchstwahrscheinlich beschädigt wird.

Nach einer Bereinigung der vorherigen Service Worker muss lediglich der Cache gelöscht werden, 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);
          }
        });
      );
    });
  );
});

Verhindern, dass sich Ihre Service Worker gegenseitig überschreiben, erfordert ein wenig Arbeit und Disziplin, aber den Aufwand lohnt sich.

Service Worker-Mentalität

Wenn Sie sich mit der richtigen Einstellung beschäftigen, während Sie über Service Worker nachdenken, können Sie Ihr Unternehmen mit Selbstvertrauen aufbauen. Sobald Sie sich mit ihnen vertraut gemacht haben, können Sie beeindruckende Erlebnisse für Ihre Nutzenden schaffen.

Wenn Sie das alles durch ein Spiel verstehen möchten, dann haben Sie Glück! In den Service-Workies lernst du, wie ein Service Worker die Monster, die offline sind, töten.