Verwenden von Service Workern zum Verwalten von Netzwerkanforderungen

Service Worker sind ein spezieller Typ von Web Workern mit der Möglichkeit, Netzwerkanforderungen mithilfe der Fetch API abzufangen, zu ändern und darauf zu reagieren. Service Worker können auf die Cache API und asynchrone clientseitige Datenspeicher wie IndexedDBzugreifen, um Ressourcen zu speichern.

Service Worker können Ihre PWA beschleunigen, indem sie Ressourcen lokal zwischenspeichern, und sie können Ihre PWA auch zuverlässiger machen, indem sie netzwerkunabhängig wird.

Wenn ein Benutzer zum ersten Mal auf Ihre PWA zugreift, wird dessen Service Worker installiert. Der Service Worker wird dann parallel zu Ihrer App ausgeführt und kann die Arbeit auch dann fortsetzen, wenn Ihre App nicht ausgeführt wird.

Service Worker sind für das Abfangen, Ändern und Reagieren auf Netzwerkanforderungen verantwortlich. Sie können benachrichtigt werden, wenn die App versucht, eine Ressource vom Server zu laden, oder eine Anforderung sendet, um Daten vom Server abzurufen. In diesem Fall kann ein Service Worker entscheiden, ob die Anforderung an den Server übertragen oder abgefangen und stattdessen eine Antwort aus dem Cache zurückgegeben wird.

Allgemeines Architekturdiagramm, das zeigt, dass sich der Service Worker zwischen der App und dem Netzwerk- und Cachespeicher befindet

Registrieren eines Service Workers

Ähnlich wie bei anderen Web Workern müssen Service Worker in einer separaten Datei vorhanden sein. Sie verweisen auf diese Datei, wenn Sie den Service Worker registrieren, wie im folgenden Code gezeigt:

if ("serviceWorker" in navigator) {
    navigator.serviceWorker.register("/serviceworker.js");
}

Der Webbrowser, in dem Ihre PWA ausgeführt wird, bietet möglicherweise unterschiedliche Supportebenen für Service Worker. Außerdem ist der Kontext, in dem Ihre PWA ausgeführt wird, möglicherweise nicht sicher. Daher empfiehlt es sich, vor dem Ausführen von Service Worker-bezogenen Code zu testen, ob das navigator.serviceWorker Objekt vorhanden ist. Im obigen Code wird ein Service Worker mithilfe der serviceworker.js Datei registriert, die sich im Stammverzeichnis der Website befindet.

Stellen Sie sicher, dass Sie die Service Worker-Datei in dem Verzeichnis der obersten Ebene ablegen, das verwaltet werden soll. Ein solches Verzeichnis wird als Bereich des Service Workers bezeichnet. Im vorherigen Code wird die Datei im Stammverzeichnis Ihrer App gespeichert, und der Service Worker verwaltet alle Seiten, die sich unter dem Domänennamen der App befinden.

Wenn die Service Worker-Datei in einem js Verzeichnis gespeichert wurde, wäre der Bereich des Service Workers auf das js Verzeichnis und alle Unterverzeichnisse beschränkt. Als bewährte Methode sollten Sie die Service Worker-Datei im Stammverzeichnis Ihrer App platzieren, es sei denn, Sie müssen den Umfang Ihres Service Workers verringern.

Abfangen von Anforderungen

Das Standard Ereignis, das Sie in einem Service Worker verwenden, ist das fetch -Ereignis. Das fetch Ereignis wird jedes Mal ausgeführt, wenn der Browser, in dem Ihre App ausgeführt wird, versucht, auf Inhalte innerhalb des Bereichs des Service Worker zuzugreifen.

Der folgende Code zeigt, wie Sie einen Listener für das fetch Ereignis hinzufügen:

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

Innerhalb des fetch Handlers können Sie steuern, ob eine Anforderung an das Netzwerk gesendet wird, pullt aus dem Cache usw. Der Ansatz, den Sie verfolgen, hängt wahrscheinlich von der Art der angeforderten Ressource, der Häufigkeit der Aktualisierung und anderen Geschäftslogik ab, die für Ihre Anwendung einzigartig ist.

Im Folgenden finden Sie einige Beispiele dafür, was Sie innerhalb des Handlers fetch tun können:

  • Wenn verfügbar, geben Sie eine Antwort aus dem Cache zurück. Andernfalls fallback zum Anfordern der Ressource über das Netzwerk.
  • Rufen Sie eine Ressource aus dem Netzwerk ab, speichern Sie eine Kopie zwischen, und geben Sie die Antwort zurück.
  • Zulassen, dass Benutzer eine Einstellung zum Speichern von Daten angeben können.
  • Geben Sie ein Platzhalterbild für bestimmte Imageanforderungen an.
  • Generieren Sie eine Antwort direkt im Service Worker.

Der Service Worker-Lebenszyklus

Der Lebenszyklus eines Service Workers besteht aus mehreren Schritten, wobei jeder Schritt ein Ereignis auslöst. Sie können diesen Ereignissen Listener hinzufügen, um Code zum Ausführen einer Aktion auszuführen. Die folgende Liste enthält eine allgemeine Ansicht des Lebenszyklus und der zugehörigen Ereignisse von Service Workern.

  1. Registrieren Sie den Service Worker.

  2. Der Browser lädt die JavaScript-Datei herunter, installiert den Service Worker und löst das install Ereignis aus. Sie können das install -Ereignis verwenden, um alle wichtigen und langlebigen Dateien (z. B. CSS-Dateien, JavaScript-Dateien, Logobilder oder Offlineseiten) aus Ihrer App vorab zwischenzuspeichern.

    self.addEventListener("install", event => {
        console.log("WORKER: install event in progress.");
    });
    
  3. Der Service Worker wird aktiviert, wodurch das activate Ereignis ausgelöst wird. Verwenden Sie dieses Ereignis, um veraltete Caches zu sauber.

    self.addEventListener("activate", event => {
        console.log("WORKER: activate event in progress.");
    });
    
  4. Der Service Worker kann ausgeführt werden, wenn die Seite aktualisiert wird oder wenn der Benutzer zu einer neuen Seite auf der Website wechselt. Wenn Sie den Service Worker ohne Wartezeit ausführen möchten, verwenden Sie die self.skipWaiting() -Methode während des install Ereignisses wie folgt:

    self.addEventListener("install", event => {
        self.skipWaiting();
        // …
    });
    
  5. Der Service Worker wird jetzt ausgeführt und kann auf fetch Ereignisse lauschen.

Zwischenspeichern von Ressourcen

Wenn ein Benutzer zum ersten Mal auf Ihre App zugreift, wird der Service Worker der App installiert. Verwenden Sie das install -Ereignis in Ihrem Service Worker, um zu erkennen, wann dies geschieht, und zwischenspeichern Sie alle statischen Ressourcen, die Ihre App benötigt. Durch das Zwischenspeichern der statischen Ressourcen Ihrer App (z. B. HTML-, CSS- und JavaScript-Code), die von der Startseite benötigt werden, kann Ihre App auch dann ausgeführt werden, wenn das Gerät des Benutzers offline ist.

Um die Ressourcen Ihrer App zwischenzuspeichern, verwenden Sie das globale caches Objekt und die cache.addAll -Methode, wie unten gezeigt:

// The name of the cache your app uses.
const CACHE_NAME = "my-app-cache";
// The list of static files your app needs to start.
const PRE_CACHED_RESOURCES = ["/", "styles.css", "app.js"];

// Listen to the `install` event.
self.addEventListener("install", event => {
  async function preCacheResources() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Cache all static resources.
    cache.addAll(PRE_CACHED_RESOURCES);
  }

  event.waitUntil(preCacheResources());
});

Beachten Sie, dass das install Ereignis nach der Erstinstallation nicht erneut ausgeführt wird. Informationen zum Aktualisieren des Codes Ihres Service Workers finden Sie unter Aktualisieren Ihres Service Workers.

Jetzt können Sie das fetch -Ereignis verwenden, um die statischen Ressourcen aus dem Cache zurückzugeben, anstatt sie erneut aus dem Netzwerk zu laden:

self.addEventListener("fetch", event => {
  async function returnCachedResource() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Find the response that was pre-cached during the `install` event.
    const cachedResponse = await cache.match(event.request.url);

    if (cachedResponse) {
      // Return the resource.
      return cachedResponse;
    } else {
      // The resource wasn't found in the cache, so fetch it from the network.
      const fetchResponse = await fetch(event.request.url);
      // Put the response in cache.
      cache.put(event.request.url, fetchResponse.clone());
      // And return the response.
      return fetchResponse.
    }
  }

  event.respondWith(returnCachedResource());
});

Aus Gründen der Übersichtlichkeit behandelt das obige Codebeispiel nicht die Fälle, in denen das Abrufen der Anforderungs-URL aus dem Netzwerk fehlgeschlagen ist.

Verwenden einer benutzerdefinierten Offlineseite

Wenn Ihre App mehrere HTML-Seiten verwendet, besteht ein gängiges Offlineszenario darin, Seitennavigationsanforderungen an eine benutzerdefinierte Fehlerseite umzuleiten, wenn das Gerät des Benutzers offline ist:

// The name of the cache your app uses.
const CACHE_NAME = "my-app-cache";
// The list of static files your app needs to start.
// Note the offline page in this list.
const PRE_CACHED_RESOURCES = ["/", "styles.css", "app.js", "/offline"];

// Listen to the `install` event.
self.addEventListener("install", event => {
  async function preCacheResources() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Cache all static resources.
    cache.addAll(PRE_CACHED_RESOURCES);
  }

  event.waitUntil(preCacheResources());
});

self.addEventListener("fetch", event => {
  async function navigateOrDisplayOfflinePage() {
    try {
      // Try to load the page from the network.
      const networkResponse = await fetch(event.request);
      return networkResponse;
    } catch (error) {
      // The network call failed, the device is offline.
      const cache = await caches.open(CACHE_NAME);
      const cachedResponse = await cache.match("/offline");
      return cachedResponse;
    }
  }

  // Only call event.respondWith() if this is a navigation request
  // for an HTML page.
  if (event.request.mode === 'navigate') {
    event.respondWith(navigateOrDisplayOfflinePage());
  }
});

Aktualisieren Ihres Service Workers

Installieren einer neuen Service Worker-Version

Wenn Sie Änderungen am Service Worker-Code vornehmen und die neue Service Worker-Datei auf Ihrem Webserver bereitstellen, wird der neue Service Worker von den Geräten Ihrer Benutzer schrittweise verwendet.

Jedes Mal, wenn ein Benutzer zu einer der Seiten Ihrer App navigiert, überprüft der Browser, in dem die App ausgeführt wird, ob eine neue Version des Service Worker auf dem Server verfügbar ist. Der Browser erkennt neue Versionen, indem der Inhalt zwischen dem vorhandenen Service Worker und dem neuen Service Worker verglichen wird. Wenn eine Änderung erkannt wird, wird der neue Service Worker installiert (dessen install Ereignis wird ausgelöst), und dann wartet der neue Service Worker darauf, dass der vorhandene Service Worker nicht mehr auf dem Gerät verwendet wird.

In der Praxis bedeutet dies, dass zwei Service Worker gleichzeitig ausgeführt werden können, aber nur einer fängt die Netzwerkanforderungen der App ab. Wenn die App geschlossen wird, wird der vorhandene Service Worker nicht mehr verwendet. Beim nächsten Öffnen der App wird der neue Service Worker aktiviert. Das activate Ereignis wird ausgelöst, und der neue Service Worker beginnt mit dem Abfangen von fetch Ereignissen.

Sie können den neuen Service Worker nach der Installation mithilfe von self.skipWaiting() im Ereignishandler Ihres Service Workers install aktivieren.

Weitere Informationen zum Aktualisieren von Service Workern finden Sie unter Aktualisieren des Service Workers auf web.dev.

Aktualisieren Ihrer zwischengespeicherten statischen Dateien

Wenn statische Ressourcen wie CSS-Stylesheetdateien vorab zwischengespeichert werden, wie unter Vorabcacheressourcen beschrieben, verwendet Ihre App nur die zwischengespeicherten Versionen der Dateien und versucht nicht, neue Versionen herunterzuladen.

Um sicherzustellen, dass Benutzer die neuesten Änderungen an den statischen Ressourcen erhalten, die von Ihrer App verwendet werden, verwenden Sie eine Zwischenspeicherungskonvention, und aktualisieren Sie Ihren Service Worker-Code.

Cache-Busting bedeutet, dass jede statische Datei gemäß ihrer Version benannt wird. Dies kann auf verschiedene Arten erreicht werden, umfasst jedoch in der Regel die Verwendung eines Buildtools, das den Inhalt einer Datei liest und basierend auf dem Inhalt eine eindeutige ID generiert. Diese ID kann zum Benennen der zwischengespeicherten statischen Datei verwendet werden.

Aktualisieren Sie als Nächstes Ihren Service Worker-Code, um die neuen statischen Ressourcen während zwischenzuspeichern install:

// The name of the new cache your app uses.
const CACHE_NAME = "my-app-cache-v2";
// The list of static files your app needs to start.
const PRE_CACHED_RESOURCES = ["/", "styles-124656.css", "app-576391.js"];

// Listen to the `install` event.
self.addEventListener("install", event => {
  async function preCacheResources() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Cache the new static resources.
    cache.addAll(PRE_CACHED_RESOURCES);
  }

  event.waitUntil(preCacheResources());
});

// Listen to the `activate` event to clear old caches.
self.addEventListener("activate", event => {
  async function deleteOldCaches() {
    // List all caches by their names.
    const names = await caches.keys();
    await Promise.all(names.map(name => {
      if (name !== CACHE_NAME) {
        // If a cache's name is the current name, delete it.
        return caches.delete(name);
      }
    }));
  }

  event.waitUntil(deleteOldCaches());
});

Vergleichen Sie die CACHE_NAME Werte und PRE_CACHED_RESOURCES zwischen dem obigen Codeausschnitt und dem Wert in Vorabcacheressourcen. Wenn dieser neue Service Worker installiert ist, wird ein neuer Cache erstellt, und die neuen statischen Ressourcen werden heruntergeladen und zwischengespeichert. Wenn der Service Worker aktiviert ist, wird der alte Cache gelöscht. An diesem Punkt verfügt der Benutzer über die neue Version der App.

Das Vornehmen von Änderungen an Ihrem Service Worker kann manchmal komplex sein. Verwenden Sie eine Bibliothek wie Workbox , um den Buildschritt für statische Ressourcen und Ihren Service Worker-Code zu vereinfachen.

Testen auf Netzwerkverbindungen in Ihrer PWA

Es ist hilfreich zu wissen, wann eine Netzwerkverbindung verfügbar ist, um Daten zu synchronisieren oder Benutzer darüber zu informieren, dass sich das Netzwerk status geändert hat.

Verwenden Sie die folgenden Optionen, um die Netzwerkkonnektivität zu testen:

Die navigator.onLine -Eigenschaft ist ein boolescher Wert, der Sie über die aktuelle status des Netzwerks informiert. Wenn der Wert ist true, ist der Benutzer online, andernfalls ist der Benutzer offline.

Weitere Informationen finden Sie unter navigator.onLine zu MDN.

Online- und Offlineereignisse

Sie können Maßnahmen ergreifen, wenn sich Ihre Netzwerkkonnektivität ändert. Sie können als Reaktion auf Netzwerkereignisse lauschen und Maßnahmen ergreifen. Die Ereignisse sind für die -, document- windowund document.body -Elemente verfügbar, wie unten gezeigt:

window.addEventListener("online",  function(){
    console.log("You are online!");
});
window.addEventListener("offline", function(){
    console.log("Oh no, you lost your network connection.");
});

Weitere Informationen finden Sie unter Navigator.onLine zu MDN.

Weitere Funktionen

Die Standard Verantwortung eines Service Workers besteht darin, Ihre App im Falle einer instabilen Netzwerkverbindung schneller und zuverlässiger zu gestalten. Service Worker verwenden dazu hauptsächlich das Ereignis und Cache die fetch API, aber sie können andere APIs für erweiterte Szenarien verwenden, z. B.:

  • Hintergrundsynchronisierung von Daten.
  • Regelmäßige Synchronisierung von Daten.
  • Downloads großer Hintergrunddateien.
  • Behandlung und Benachrichtigungen von Pushnachrichten.

Hintergrundsynchronisierung

Verwenden Sie die Hintergrundsynchronisierungs-API, damit Benutzer Ihre App weiterhin verwenden und Aktionen ausführen können, auch wenn das Gerät des Benutzers offline ist.

Beispielsweise kann eine E-Mail-App ihren Benutzern jederzeit das Verfassen und Senden von Nachrichten ermöglichen. Das App-Front-End kann versuchen, die Nachricht sofort zu senden. Wenn das Gerät offline ist, kann der Service Worker die fehlgeschlagene Anforderung abfangen und die Hintergrundsynchronisierungs-API verwenden, um die Aufgabe zurückzuziehen, bis die Verbindung hergestellt ist.

Weitere Informationen finden Sie unter Verwenden der Hintergrundsynchronisierungs-API zum Synchronisieren von Daten mit dem Server.

Periodenhintergrundsynchronisierung

Mit der API für die regelmäßige Hintergrundsynchronisierung können PWAs in regelmäßigen Abständen neue Inhalte im Hintergrund abrufen, sodass Benutzer sofort auf den Inhalt zugreifen können, wenn sie die App später erneut öffnen.

Mithilfe der API für die regelmäßige Hintergrundsynchronisierung müssen PWAs keine neuen Inhalte (z. B. neue Artikel) herunterladen, während der Benutzer die App verwendet. Das Herunterladen von Inhalten könnte die Erfahrung verlangsamen, sodass die App den Inhalt zu einem günstigeren Zeitpunkt abrufen kann.

Weitere Informationen finden Sie unter Verwenden der API für die regelmäßige Hintergrundsynchronisierung, um regelmäßig neue Inhalte zu erhalten.

Downloads großer Hintergrunddateien

Die Background Fetch-API ermöglicht PWAs, das Herunterladen großer Datenmengen vollständig an die Browser-Engine zu delegieren. Auf diese Weise müssen die App und der Service Worker nicht ausgeführt werden, während der Download ausgeführt wird.

Diese API ist nützlich für Apps, mit denen Benutzer große Dateien (z. B. Musik, Filme oder Podcasts) für Offlineanwendungsfälle herunterladen können. Der Download wird an die Browser-Engine delegiert, die eine zeitweilige Verbindung oder sogar einen vollständigen Konnektivitätsverlust zu behandeln weiß.

Weitere Informationen finden Sie unter Verwenden der Hintergrundabruf-API zum Abrufen großer Dateien, wenn die App oder der Service Worker nicht ausgeführt wird.

Pushnachrichten

Pushnachrichten können an Ihre Benutzer gesendet werden, ohne dass sie die App zu diesem Zeitpunkt verwenden müssen. Ein Service Worker kann Pushnachrichten lauschen, die von Ihrem Server gesendet werden, auch wenn die App nicht ausgeführt wird, und eine Benachrichtigung im Benachrichtigungscenter des Betriebssystems anzeigen.

Weitere Informationen finden Sie unter Erneutes Einbinden von Benutzern mit Pushnachrichten.

Debuggen mit DevTools

Mithilfe von Microsoft Edge DevTools können Sie sehen, ob Ihr Service Worker ordnungsgemäß registriert wurde, und sehen, in welchem Lebenszykluszustand sich der Service Worker derzeit befindet. Außerdem können Sie den JavaScript-Code in Ihrem Service Worker debuggen.

Weitere Informationen finden Sie unter Debuggen Ihres Service Workers.

Siehe auch