Service Worker scripten

Dieses Codelab ist Teil des Kurses „Progressive Web-Apps entwickeln“, der vom Google Developers Training-Team entwickelt wurde. Sie können den größten Nutzen aus diesem Kurs ziehen, wenn Sie die Codelabs der Reihe nach durcharbeiten.

Weitere Informationen zum Kurs

Einführung

In diesem Lab erfahren Sie, wie Sie einen einfachen Service Worker erstellen und wie der Lebenszyklus eines Service Workers aussieht.

Lerninhalte

  • Einfaches Service Worker-Skript erstellen, installieren und debuggen

Wichtige Informationen

  • Einfaches JavaScript und HTML
  • Konzepte und grundlegende Syntax von ES2015-Promises
  • Entwicklerkonsole aktivieren

Voraussetzungen

Laden Sie das Repository „pwa-training-labs“ von GitHub herunter oder klonen Sie es und installieren Sie bei Bedarf die LTS-Version von Node.js.

Wechseln Sie in das Verzeichnis service-worker-lab/app/ und starten Sie einen lokalen Entwicklungsserver:

cd service-worker-lab/app
npm install
node server.js

Sie können den Server jederzeit mit Ctrl-c beenden.

Öffnen Sie Ihren Browser und rufen Sie localhost:8081/ auf.

Hinweis:Melden Sie alle Service Worker ab und löschen Sie alle Service Worker-Caches für localhost, damit sie das Lab nicht beeinträchtigen. In den Chrome-Entwicklertools können Sie dazu auf dem Tab Anwendung im Bereich Speicher löschen auf Websitedaten löschen klicken.

Öffnen Sie den Ordner service-worker-lab/app/ in Ihrem bevorzugten Texteditor. Im Ordner app/ erstellen Sie das Lab.

Dieser Ordner enthält:

  • below/another.html, js/another.js, js/other.js und other.html sind Beispielressourcen, mit denen wir den Service Worker-Bereich testen.
  • Der Ordner styles/ enthält die Cascading Stylesheets für dieses Lab.
  • Der Ordner test/ enthält Dateien zum Testen Ihres Fortschritts.
  • index.html ist die Haupt-HTML-Seite für unsere Beispielwebsite/-anwendung.
  • service-worker.js ist die JavaScript-Datei, die zum Erstellen unseres Service Workers verwendet wird.
  • package.json und package-lock.json verfolgen die in diesem Projekt verwendeten Knotenpakete.
  • server.js ist ein einfacher Express-Server, auf dem wir unsere App hosten.

Öffnen Sie service-worker.js in einem Texteditor. Die Datei ist leer. Wir haben noch keinen Code hinzugefügt, der im Service Worker ausgeführt werden soll.

Öffnen Sie index.html in einem Texteditor.

Fügen Sie den folgenden Code zwischen den <script>-Tags ein, um den Service Worker zu registrieren:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('Service Worker is registered', registration);
    })
    .catch(err => {
      console.error('Registration failed:', err);
    });
  });
}

Speichern Sie das Skript und aktualisieren Sie die Seite. In der Konsole sollte eine Meldung angezeigt werden, dass der Service Worker registriert wurde. In Chrome können Sie prüfen, ob ein Service Worker registriert ist. Öffnen Sie dazu die Entwicklertools (Strg + Umschalttaste + I unter Windows und Linux oder ⌘ + Wahltaste + I auf dem Mac), klicken Sie auf den Tab „Anwendung“ und dann auf die Option Service Workers. Die Ausgabe sollte in etwa so aussehen:

Optional: Öffnen Sie die Website in einem nicht unterstützten Browser und prüfen Sie, ob die Bedingung für die Browserunterstützung funktioniert.

Erklärung

Mit dem obigen Code wird die Datei service-worker.js als Service Worker registriert. Zuerst wird geprüft, ob der Browser Service Worker unterstützt. Dies sollte jedes Mal erfolgen, wenn Sie einen Service Worker registrieren, da einige Browser Service Worker möglicherweise nicht unterstützen. Der Code registriert dann den Service Worker mit der Methode register der ServiceWorkerContainer API, die im Navigator-Interface des Fensters enthalten ist.

navigator.serviceWorker.register(...) gibt ein Promise zurück, das mit einem registration-Objekt aufgelöst wird, sobald der Service Worker erfolgreich registriert wurde. Wenn die Registrierung fehlschlägt, wird das Promise abgelehnt.

Änderungen am Status des Service Workers lösen Ereignisse im Service Worker aus.

Event-Listener hinzufügen

Öffnen Sie service-worker.js in einem Texteditor.

Fügen Sie dem Service Worker die folgenden Event-Listener hinzu:

self.addEventListener('install', event => {
  console.log('Service worker installing...');
  // Add a call to skipWaiting here
});

self.addEventListener('activate', event => {
  console.log('Service worker activating...');
});

Speichern Sie die Datei.

Heben Sie die Registrierung des Service Workers manuell auf und aktualisieren Sie die Seite, um den aktualisierten Service Worker zu installieren und zu aktivieren. Das Konsolenlog sollte darauf hinweisen, dass der neue Service Worker registriert, installiert und aktiviert wurde.

Hinweis : Das Registrierungsprotokoll wird möglicherweise nicht in der richtigen Reihenfolge mit den anderen Protokollen (Installation und Aktivierung) angezeigt. Der Service Worker wird gleichzeitig mit der Seite ausgeführt. Daher können wir die Reihenfolge der Logs nicht garantieren. Das Registrierungslog stammt von der Seite, während die Installations- und Aktivierungslogs vom Service Worker stammen. Installations-, Aktivierungs- und andere Service Worker-Ereignisse treten jedoch in einer bestimmten Reihenfolge innerhalb des Service Workers auf und sollten immer in der erwarteten Reihenfolge angezeigt werden.

Erklärung

Der Service Worker gibt am Ende der Registrierung ein install-Ereignis aus. Im obigen Code wird eine Nachricht im install-Event-Listener protokolliert. In einer echten App wäre dies jedoch ein guter Ort, um statische Assets zu cachen.

Wenn ein Service Worker registriert ist, erkennt der Browser, ob der Service Worker neu ist. Das ist der Fall, wenn er sich vom zuvor installierten Service Worker unterscheidet oder wenn für diese Website kein Service Worker registriert ist. Wenn der Service Worker neu ist (wie in diesem Fall), wird er vom Browser installiert.

Der Service Worker gibt ein activate-Ereignis aus, wenn er die Kontrolle über die Seite übernimmt. Im obigen Code wird hier eine Nachricht protokolliert. Dieses Ereignis wird jedoch häufig zum Aktualisieren von Caches verwendet.

Für einen bestimmten Bereich kann immer nur ein Service Worker aktiv sein (siehe „Service Worker-Bereich“). Ein neu installierter Service Worker wird also erst aktiviert, wenn der vorhandene Service Worker nicht mehr verwendet wird. Deshalb müssen alle Seiten, die von einem Service Worker gesteuert werden, geschlossen werden, bevor ein neuer Service Worker die Kontrolle übernehmen kann. Da wir den vorhandenen Service Worker abgemeldet haben, wurde der neue Service Worker sofort aktiviert.

Hinweis:Das bloße Aktualisieren der Seite reicht nicht aus, um die Steuerung an einen neuen Service Worker zu übertragen, da die neue Seite angefordert wird, bevor die aktuelle Seite entladen wird. Es gibt also keinen Zeitpunkt, an dem der alte Service Worker nicht verwendet wird.

Hinweis:Sie können einen neuen Service Worker auch manuell über das Entwicklertool einiger Browser und programmatisch mit skipWaiting() aktivieren. Das wird in Abschnitt 3.4 beschrieben.

Service Worker aktualisieren

Fügen Sie den folgenden Kommentar an einer beliebigen Stelle in service-worker.js ein:

// I'm a new service worker

Speichern Sie die Datei und aktualisieren Sie die Seite. Sehen Sie sich die Logs in der Konsole an. Der neue Service Worker wird installiert, aber nicht aktiviert. In Chrome können Sie den wartenden Service Worker in den Entwicklertools auf dem Tab Anwendung sehen.

Schließen Sie alle Seiten, die mit dem Service Worker verknüpft sind. Öffnen Sie dann localhost:8081/ wieder. Im Konsolenlog sollte angezeigt werden, dass der neue Service Worker jetzt aktiviert wurde.

Hinweis:Wenn Sie unerwartete Ergebnisse erhalten, prüfen Sie, ob der HTTP-Cache in den Entwicklertools deaktiviert ist.

Erklärung

Der Browser erkennt einen Byte-Unterschied zwischen der neuen und der vorhandenen Service Worker-Datei (aufgrund des hinzugefügten Kommentars), sodass der neue Service Worker installiert wird. Da immer nur ein Service Worker für einen bestimmten Bereich aktiv sein kann, wird der neue Service Worker erst aktiviert, wenn der vorhandene Service Worker nicht mehr verwendet wird. Wenn wir alle Seiten schließen, die vom alten Service Worker gesteuert werden, können wir den neuen Service Worker aktivieren.

Wartephase überspringen

Ein neuer Service Worker kann sofort aktiviert werden, auch wenn ein vorhandener Service Worker vorhanden ist. Dazu muss die Wartephase übersprungen werden.

Fügen Sie in service-worker.js einen Aufruf von skipWaiting in den install-Event-Listener ein:

self.skipWaiting();

Speichern Sie die Datei und aktualisieren Sie die Seite. Der neue Service Worker wird sofort installiert und aktiviert, auch wenn ein vorheriger Service Worker aktiv war.

Erklärung

Mit der Methode skipWaiting() kann ein Service Worker aktiviert werden, sobald die Installation abgeschlossen ist. Der Event-Listener für die Installation ist ein guter Ort für den skipWaiting()-Aufruf, er kann aber auch an einer beliebigen anderen Stelle während oder vor der Wartephase erfolgen. Weitere Informationen dazu, wann und wie skipWaiting() verwendet werden sollte Für den Rest des Labs können wir jetzt neuen Service Worker-Code testen, ohne den Service Worker manuell abzumelden.

Weitere Informationen

Service Worker können als Proxy zwischen Ihrer Web-App und dem Netzwerk fungieren.

Fügen wir einen Fetch-Listener hinzu, um Anfragen von unserer Domain abzufangen.

Fügen Sie den folgenden Code zu service-worker.js hinzu:

self.addEventListener('fetch', event => {
  console.log('Fetching:', event.request.url);
});

Speichern Sie das Skript und aktualisieren Sie die Seite, um den aktualisierten Service Worker zu installieren und zu aktivieren.

Prüfen Sie die Konsole. Es sollten keine Fetch-Ereignisse protokolliert worden sein. Aktualisieren Sie die Seite und sehen Sie noch einmal in der Konsole nach. Diesmal sollten Abrufe für die Seite und ihre Assets (z. B. CSS) zu sehen sein.

Klicken Sie auf die Links Other page (Andere Seite), Another page (Eine weitere Seite) und Back (Zurück).

In der Konsole werden Abrufvorgänge für jede Seite und ihre Assets angezeigt. Ergeben alle Logs Sinn?

Hinweis:Wenn Sie eine Seite aufrufen und der HTTP-Cache nicht deaktiviert ist, werden CSS- und JavaScript-Assets möglicherweise lokal im Cache gespeichert. In diesem Fall werden keine Abrufe für diese Ressourcen angezeigt.

Erklärung

Der Service Worker empfängt für jede HTTP-Anfrage, die vom Browser innerhalb seines Bereichs gestellt wird, ein Fetch-Ereignis. Das Fetch-Ereignisobjekt enthält die Anfrage. Das Abfangen von Fetch-Ereignissen im Service Worker ähnelt dem Abfangen von Click-Ereignissen im DOM. In unserem Code protokollieren wir die angeforderte URL in der Konsole, wenn ein Fetch-Ereignis eintritt. In der Praxis könnten wir auch eine eigene benutzerdefinierte Antwort mit beliebigen Ressourcen erstellen und zurückgeben.

Warum wurden beim ersten Aktualisieren keine Abrufevents protokolliert? Standardmäßig werden Abrufe von einer Seite nicht über einen Service Worker ausgeführt, es sei denn, die Seitenanfrage selbst wurde über einen Service Worker gesendet. So wird die Konsistenz Ihrer Website gewährleistet. Wenn eine Seite ohne den Service Worker geladen wird, werden auch die zugehörigen Unterressourcen ohne den Service Worker geladen.

Weitere Informationen

Lösungscode

Wenn Sie eine Kopie des funktionierenden Codes erhalten möchten, rufen Sie den Ordner 04-intercepting-network-requests/ auf.

Service Worker haben einen Bereich. Der Umfang des Service Workers bestimmt, von welchen Pfaden der Service Worker Anfragen abfängt.

Bereich finden

Aktualisieren Sie den Registrierungscode in index.html mit:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('SW registered with scope:', registration.scope);
    })
    .catch(err => {
      console.error('Registration failed:', err);
    });
  });
}

Aktualisieren Sie die Browserseite. Beachten Sie, dass in der Konsole der Bereich des Service Workers angezeigt wird (in diesem Fall http://localhost:8081/).

Erklärung

Das von register() zurückgegebene Promise wird zum Registrierungsobjekt aufgelöst, das den Bereich des Service Workers enthält.

Der Standardbereich ist der Pfad zur Service Worker-Datei und erstreckt sich auf alle untergeordneten Verzeichnisse. Ein Service Worker im Stammverzeichnis einer App steuert also Anfragen von allen Dateien in der App.

Service Worker verschieben

Verschieben Sie service-worker.js in das Verzeichnis below/ und aktualisieren Sie die Service Worker-URL im Registrierungscode in index.html.

Melden Sie den aktuellen Service Worker im Browser ab und aktualisieren Sie die Seite.

In der Console wird angezeigt, dass der Bereich des Service Workers jetzt http://localhost:8081/below/ ist. In Chrome können Sie den Service Worker-Bereich auch auf dem Tab „Anwendung“ der Entwicklertools sehen:

Klicken Sie auf der Hauptseite auf Andere Seite, Weitere Seite und Zurück. Welche Abrufanfragen werden protokolliert? Welche nicht?

Erklärung

Der Standardbereich des Service Workers ist der Pfad zur Service Worker-Datei. Da sich die Service Worker-Datei jetzt in below/ befindet, ist das ihr Bereich. In der Konsole werden jetzt nur noch Fetch-Ereignisse für another.html, another.css und another.js protokolliert, da dies die einzigen Ressourcen im Zuständigkeitsbereich des Service Workers sind.

Beliebigen Bereich festlegen

Verschieben Sie den Service Worker zurück in das Stammverzeichnis des Projekts (app/) und aktualisieren Sie die Service Worker-URL im Registrierungscode in index.html.

Verwenden Sie die Referenz auf MDN, um den Bereich des Service Workers mit dem optionalen Parameter in register() auf das Verzeichnis below/ festzulegen.

Melden Sie den Service Worker ab und aktualisieren Sie die Seite. Klicken Sie auf Andere Seite, Eine andere Seite und Zurück.

Die Konsole zeigt wieder, dass der Bereich des Service Workers jetzt http://localhost:8081/below/ ist und Fetch-Ereignisse nur für another.html, another.css und another.js protokolliert werden.

Erklärung

Beim Registrieren kann ein beliebiger Bereich festgelegt werden, indem ein zusätzlicher Parameter übergeben wird, z. B.:

navigator.serviceWorker.register('/service-worker.js', {
  scope: '/kitten/'
});

Im obigen Beispiel ist der Bereich des Service Workers auf /kitten/ festgelegt. Der Service Worker fängt Anfragen von Seiten in /kitten/ und /kitten/lower/ ab, nicht aber von Seiten wie /kitten oder /.

Hinweis:Sie können keinen beliebigen Bereich festlegen, der über dem tatsächlichen Speicherort des Service Workers liegt. Wenn Ihr Service Worker jedoch auf einem Client aktiv ist, der mit dem Service-Worker-Allowed-Header bereitgestellt wird, können Sie einen maximalen Bereich für diesen Service Worker über dem Speicherort des Service Workers angeben.

Weitere Informationen

Lösungscode

Wenn Sie eine Kopie des funktionierenden Codes erhalten möchten, rufen Sie den Ordner solution/ auf.

Sie haben jetzt einen einfachen Service Worker, der ausgeführt wird, und kennen den Lebenszyklus von Service Workern.

Weitere Informationen

Service Worker-Lebenszyklus

Eine Liste aller Codelabs im PWA-Schulungskurs finden Sie im Willkommens-Codelab für den Kurs.