Bereitstellung

Ein wichtiger Aspekt von progressiven Web-Apps ist ihre Zuverlässigkeit. Sie können Assets schnell laden, sodass Nutzer nicht abspringen und sofort Feedback erhalten, auch bei schlechten Netzwerkbedingungen. Wie ist das möglich? Dank des fetch-Ereignisses des Service Workers.

Das Abrufevent

Browser Support

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

Source

Mit dem Ereignis fetch können wir jede Netzwerkanfrage abfangen, die von der PWA im Bereich des Service Workers gestellt wird, sowohl für Anfragen mit demselben Ursprung als auch für ursprungsübergreifende Anfragen. Neben Navigations- und Asset-Anfragen ermöglicht das Abrufen von einem installierten Service Worker, dass Seitenbesuche nach dem ersten Laden einer Website ohne Netzwerkaufrufe gerendert werden.

Der fetch-Handler empfängt alle Anfragen von einer App, einschließlich URLs und HTTP-Headern, und der App-Entwickler kann entscheiden, wie sie verarbeitet werden.

Der Service Worker befindet sich zwischen dem Client und dem Netzwerk.

Ihr Service Worker kann eine Anfrage an das Netzwerk weiterleiten, mit einer zuvor im Cache gespeicherten Antwort antworten oder eine neue Antwort erstellen. Die Entscheidung liegt ganz bei dir. Hier ein einfaches Beispiel:

self.addEventListener("fetch", event => {
    console.log(`URL requested: ${event.request.url}`);
});

Auf eine Anfrage antworten

Wenn eine Anfrage in Ihrem Service Worker eingeht, haben Sie zwei Möglichkeiten: Sie können sie ignorieren, sodass sie an das Netzwerk weitergeleitet wird, oder Sie können darauf reagieren. Wenn Sie auf Anfragen in Ihrem Service Worker antworten, können Sie festlegen, was und wie es an Ihre PWA zurückgegeben wird, auch wenn der Nutzer offline ist.

So antworten Sie auf eine eingehende Anfrage: Rufen Sie event.respondWith() in einem fetch-Event-Handler auf:

// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
    const response = .... // a response or a Promise of response
    event.respondWith(response);
});

Sie müssen respondWith() synchron aufrufen und ein Response-Objekt zurückgeben. Sie können respondWith() jedoch nicht aufrufen, nachdem der Fetch-Event-Handler abgeschlossen ist, z. B. in einem asynchronen Aufruf. Wenn Sie auf die vollständige Antwort warten müssen, können Sie ein Promise an respondWith() übergeben, das mit einer Response aufgelöst wird.

Antworten erstellen

Dank der Fetch API können Sie HTTP-Antworten in Ihrem JavaScript-Code erstellen. Diese Antworten können mit der Cache Storage API im Cache gespeichert und so zurückgegeben werden, als kämen sie von einem Webserver.

Um eine Antwort zu erstellen, erstellen Sie ein neues Response-Objekt und legen Sie dessen Text und Optionen wie Status und Header fest:

const simpleResponse = new Response("Body of the HTTP response");

const options = {
   status: 200,
   headers: {
    'Content-type': 'text/html'
   }
};
const htmlResponse = new Response("<b>HTML</b> content", options)

Antworten aus dem Cache

Nachdem Sie nun wissen, wie Sie HTTP-Antworten von einem Service Worker bereitstellen, ist es an der Zeit, die Caching Storage API zu verwenden, um Assets auf dem Gerät zu speichern.

Mit der Cache Storage API können Sie prüfen, ob die von der PWA empfangene Anfrage im Cache verfügbar ist. Wenn ja, können Sie mit der Anfrage auf respondWith() antworten. Dazu müssen Sie zuerst im Cache suchen. Die Funktion match() ist in der caches-Schnittstelle der obersten Ebene verfügbar und durchsucht alle Speicher in Ihrem Ursprung oder ein einzelnes offenes Cache-Objekt.

Die Funktion match() empfängt eine HTTP-Anfrage oder eine URL als Argument und gibt ein Promise zurück, das mit der Antwort aufgelöst wird, die dem entsprechenden Schlüssel zugeordnet ist.

// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
   console.log(response ? response : "It's not in the cache");
});

// Cache-specific search
caches.open("pwa-assets").then(cache => {
  cache.match(urlOrRequest).then(response => {
    console.log(response ? response : "It's not in the cache");
  });
});

Caching-Strategien

Dateien nur aus dem Browsercache bereitzustellen, ist nicht für jeden Anwendungsfall geeignet. Der Cache kann beispielsweise vom Nutzer oder vom Browser geleert werden. Deshalb sollten Sie eigene Strategien für die Bereitstellung von Assets für Ihre PWA definieren. Sie sind nicht auf eine Caching-Strategie beschränkt. Sie können für verschiedene URL-Muster unterschiedliche Werte definieren. Sie können beispielsweise eine Strategie für die Mindestanzahl an UI-Assets, eine für API-Aufrufe und eine dritte für Bild- und Daten-URLs haben. Lesen Sie dazu event.request.url in ServiceWorkerGlobalScope.onfetch und parsen Sie sie mit regulären Ausdrücken oder einem URL-Muster. (Zum Zeitpunkt der Erstellung dieses Artikels wird das URL-Muster nicht auf allen Plattformen unterstützt.)

Die gängigsten Strategien sind:

Cache First
Sucht zuerst nach einer im Cache gespeicherten Antwort und greift auf das Netzwerk zurück, wenn keine gefunden wird.
Netzwerk zuerst
Fordert zuerst eine Antwort vom Netzwerk an. Wenn keine zurückgegeben wird, wird im Cache nach einer Antwort gesucht.
„Stale While Revalidate“
Stellt eine Antwort aus dem Cache bereit, während im Hintergrund die neueste Version angefordert und für die nächste Anfrage des Assets im Cache gespeichert wird.
Nur Netzwerk
Antwortet immer mit einer Antwort aus dem Netzwerk oder gibt einen Fehler aus. Der Cache wird nie berücksichtigt.
Nur Cache
Antwortet immer mit einer Antwort aus dem Cache oder gibt einen Fehler aus. Das Netzwerk wird nie konsultiert. Die Assets, die mit dieser Strategie bereitgestellt werden, müssen dem Cache hinzugefügt werden, bevor sie angefordert werden.

Cache zuerst

Bei dieser Strategie sucht der Service Worker im Cache nach der passenden Anfrage und gibt die entsprechende Antwort zurück, wenn sie im Cache gespeichert ist. Andernfalls wird die Antwort aus dem Netzwerk abgerufen und der Cache wird optional für zukünftige Aufrufe aktualisiert. Wenn es weder eine Cache- noch eine Netzwerkantwort gibt, tritt bei der Anfrage ein Fehler auf. Da das Bereitstellen von Assets ohne Netzwerkzugriff in der Regel schneller ist, wird bei dieser Strategie die Leistung gegenüber der Aktualität priorisiert.

Die Cache-First-Strategie

self.addEventListener("fetch", event => {
   event.respondWith(
     caches.match(event.request)
     .then(cachedResponse => {
       // It can update the cache to serve updated content on the next request
         return cachedResponse || fetch(event.request);
     }
   )
  )
});

Netzwerk zuerst

Diese Strategie ist das Spiegelbild der „Cache First“-Strategie. Sie prüft, ob die Anfrage über das Netzwerk erfüllt werden kann, und versucht, sie aus dem Cache abzurufen, wenn dies nicht möglich ist. Wie „Cache First“. Wenn es weder eine Netzwerk- noch eine Cache-Antwort gibt, schlägt die Anfrage fehl. Das Abrufen der Antwort aus dem Netzwerk ist in der Regel langsamer als das Abrufen aus dem Cache. Bei dieser Strategie wird aktualisierten Inhalten Vorrang vor der Leistung eingeräumt.

Die Network-First-Strategie

self.addEventListener("fetch", event => {
   event.respondWith(
     fetch(event.request)
     .catch(error => {
       return caches.match(event.request) ;
     })
   );
});

Veraltet bei erneuter Validierung

Bei der Strategie „Stale While Revalidate“ wird sofort eine im Cache gespeicherte Antwort zurückgegeben. Anschließend wird das Netzwerk auf ein Update geprüft und die im Cache gespeicherte Antwort wird ersetzt, wenn ein Update gefunden wird. Bei dieser Strategie wird immer eine Netzwerkanfrage gesendet, da auch wenn eine zwischengespeicherte Ressource gefunden wird, versucht wird, den Cache mit den vom Netzwerk empfangenen Daten zu aktualisieren, um die aktualisierte Version in der nächsten Anfrage zu verwenden. Diese Strategie bietet Ihnen daher die Möglichkeit, von der schnellen Bereitstellung des Caches zu profitieren und den Cache im Hintergrund zu aktualisieren.

Die Strategie „Veraltete Inhalte bei nochmaliger Validierung bereitstellen“

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
        const networkFetch = fetch(event.request).then(response => {
          // update the cache with a clone of the network response
          const responseClone = response.clone()
          caches.open(url.searchParams.get('name')).then(cache => {
            cache.put(event.request, responseClone)
          })
          return response
        }).catch(function (reason) {
          console.error('ServiceWorker fetch failed: ', reason)
        })
        // prioritize cached response over network
        return cachedResponse || networkFetch
      }
    )
  )
})

Nur Netzwerk

Die Strategie „Nur Netzwerk“ ähnelt dem Verhalten von Browsern ohne Service Worker oder Cache Storage API. Bei Anfragen wird nur dann eine Ressource zurückgegeben, wenn sie aus dem Netzwerk abgerufen werden kann. Das ist oft nützlich für Ressourcen wie reine Online-API-Anfragen.

Strategie „Nur Netzwerk“

Nur Cache

Bei der Strategie „Nur Cache“ werden Anfragen nie an das Netzwerk gesendet. Alle eingehenden Anfragen werden mit einem vorab gefüllten Cache-Element beantwortet. Im folgenden Code wird der Ereignishandler fetch mit der Methode match des Cache-Speichers verwendet, um nur auf den Cache zu reagieren:

self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});

Nur-Cache-Strategie.

Benutzerdefinierte Strategien

Die oben genannten Caching-Strategien sind zwar gängig, aber Sie sind für Ihren Service Worker und die Verarbeitung von Anfragen verantwortlich. Wenn keine dieser Optionen Ihren Anforderungen entspricht, können Sie eine eigene erstellen.

Sie können beispielsweise eine „Network First“-Strategie mit einem Zeitlimit verwenden, um aktualisierte Inhalte zu priorisieren, aber nur, wenn die Antwort innerhalb eines von Ihnen festgelegten Schwellenwerts angezeigt wird. Sie können auch eine im Cache gespeicherte Antwort mit einer Netzwerkantwort zusammenführen und eine komplexe Antwort aus dem Service Worker erstellen.

Assets aktualisieren

Es kann schwierig sein, die im Cache gespeicherten Assets Ihrer PWA auf dem neuesten Stand zu halten. Die Strategie „Stale-while-revalidate“ ist eine Möglichkeit, dies zu erreichen, aber nicht die einzige. Im Kapitel „Aktualisieren“ erfahren Sie mehr über verschiedene Techniken, mit denen Sie die Inhalte und Assets Ihrer App auf dem neuesten Stand halten können.

Ressourcen