Aktuellere Service-Worker (Standard)

Jan Posnick
Jeff Posnick

tl;dr

Ab Chrome 68 werden HTTP-Anfragen, die nach Updates für das Service Worker-Skript suchen, nicht mehr standardmäßig vom HTTP-Cache verarbeitet. Damit lässt sich ein häufiges Problem für Entwickler umgehen, bei dem ein versehentlicher Cache-Control-Header in Ihrem Service Worker-Skript zu verzögerten Updates führen kann.

Wenn Sie das HTTP-Caching für Ihr Skript /service-worker.js bereits deaktiviert haben, indem Sie es mit Cache-Control: max-age=0 bereitgestellt haben, sollten Sie aufgrund des neuen Standardverhaltens keine Änderungen sehen.

Außerdem wird ab Chrome 78 der Byte-für-Byte-Vergleich auf Skripts angewendet, die über importScripts() in einem Service Worker geladen werden. Jede Änderung an einem importierten Skript löst den Service Worker-Aktualisierungsablauf aus, genau wie eine Änderung am Service Worker der obersten Ebene.

Hintergrund

Jedes Mal, wenn Sie eine neue Seite aufrufen, die im Geltungsbereich eines Service Workers liegt, registration.update() explizit aus JavaScript aufrufen oder wenn ein Service Worker durch ein push- oder sync-Ereignis „geweckt“ wird, fordert der Browser gleichzeitig die JavaScript-Ressource an, die ursprünglich an den navigator.serviceWorker.register()-Aufruf übergeben wurde, um nach Aktualisierungen des Service Worker-Skripts zu suchen.

In diesem Artikel nehmen wir an, dass die URL /service-worker.js lautet und dass sie einen einzelnen Aufruf von importScripts() enthält, durch den zusätzlicher Code geladen wird, der innerhalb des Service Workers ausgeführt wird:

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

Was ändert sich?

Vor Chrome 68 wurde die Aktualisierungsanfrage für /service-worker.js wie bei den meisten Abrufen über den HTTP-Cache gestellt. Das bedeutet, wenn das Skript ursprünglich mit Cache-Control: max-age=600 gesendet wurde, würden Aktualisierungen innerhalb der nächsten 600 Sekunden (10 Minuten) nicht an das Netzwerk gesendet werden, sodass der Nutzer möglicherweise nicht die aktuelle Version des Service Workers erhält. Wenn max-age jedoch größer als 86.400 (24 Stunden) wäre, würde es wie 86.400 behandelt, um zu vermeiden, dass Nutzer dauerhaft bei einer bestimmten Version hängen bleiben.

Ab Version 68 wird der HTTP-Cache ignoriert, wenn Aktualisierungen für das Service Worker-Skript angefordert werden. Daher kann es bei vorhandenen Webanwendungen zu einer höheren Häufigkeit von Anfragen für ihr Service Worker-Skript kommen. Anfragen für importScripts erfolgen weiterhin über den HTTP-Cache. Dies ist jedoch nur die Standardeinstellung. Mit der neuen Registrierungsoption updateViaCache lässt sich dieses Verhalten steuern.

updateViaCache

Entwickler können beim Aufrufen von navigator.serviceWorker.register() jetzt eine neue Option übergeben: den Parameter updateViaCache. Sie verwendet einen von drei Werten: 'imports', 'all' oder 'none'.

Die Werte bestimmen, ob und wie der Standard-HTTP-Cache des Browsers ins Spiel kommt, wenn die HTTP-Anfrage zur Prüfung auf aktualisierte Service-Worker-Ressourcen gestellt wird.

  • Wenn 'imports' festgelegt ist, wird der HTTP-Cache bei der Suche nach Updates für das Skript /service-worker.js nie abgerufen, aber beim Abrufen von importierten Skripts berücksichtigt (in unserem Beispiel path/to/import.js). Das ist die Standardeinstellung und entspricht dem Verhalten ab Chrome 68.

  • Wenn 'all' festgelegt ist, wird der HTTP-Cache bei Anfragen für das Skript /service-worker.js der obersten Ebene sowie für alle innerhalb des Service Worker importierten Skripts wie path/to/import.js herangezogen. Diese Option entspricht dem vorherigen Verhalten in Chrome vor Chrome 68.

  • Wenn 'none' festgelegt ist, wird der HTTP-Cache nicht herangezogen, wenn Anfragen für /service-worker.js der obersten Ebene oder importierte Skripts wie das hypothetische path/to/import.js gestellt werden.

Mit dem folgenden Code wird beispielsweise ein Service Worker registriert und sichergestellt, dass bei der Suche nach Aktualisierungen des Skripts /service-worker.js oder Skripts, auf die über importScripts() in /service-worker.js verwiesen wird, nie der HTTP-Cache konsultiert wird:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

Suche nach Aktualisierungen für importierte Skripts

Vor Chrome 78 wurde jedes über importScripts() geladene Service Worker-Skript nur einmal abgerufen. Je nach updateViaCache-Konfiguration wurde es zuerst aus dem HTTP-Cache oder über das Netzwerk geprüft. Nach diesem ersten Abruf wird sie intern vom Browser gespeichert und nicht noch einmal abgerufen.

Die einzige Möglichkeit, einen bereits installierten Service Worker zur Übernahme von Änderungen an einem importierten Skript zu zwingen, bestand darin, die URL des Skripts zu ändern. Dies bestand in der Regel entweder durch Hinzufügen eines semver-Werts (z. B. importScripts('https://example.com/v1.1.0/index.js')) oder durch Einbinden eines Hashwerts des Inhalts (z. B. importScripts('https://example.com/index.abcd1234.js')). Wenn Sie die importierte URL ändern, ändert sich der Inhalt des Service Worker-Skripts auf oberster Ebene.

Ab Chrome 78 wird jedes Mal, wenn eine Update-Prüfung für eine Service Worker-Datei der obersten Ebene durchgeführt wird, gleichzeitig geprüft, ob sich der Inhalt importierter Skripts geändert hat. Abhängig von den verwendeten Cache-Control-Headern werden diese importierten Skriptprüfungen möglicherweise vom HTTP-Cache ausgeführt, wenn updateViaCache auf 'all' oder 'imports' (Standardwert) gesetzt ist. Sie können auch direkt an das Netzwerk gesendet werden, wenn updateViaCache auf 'none' gesetzt ist.

Wenn die Aktualisierungsprüfung für ein importiertes Skript zu einem Byte-für-Byte-Unterschied im Vergleich zu dem führt, was zuvor vom Service Worker gespeichert wurde, löst dies wiederum den gesamten Aktualisierungsablauf des Service Workers aus, selbst wenn die Service Worker-Datei der obersten Ebene unverändert bleibt.

Das Verhalten von Chrome 78 entspricht dem, was Firefox vor einigen Jahren in Firefox 56 implementiert hat. Safari implementiert dieses Verhalten bereits.

Was müssen Entwickler tun?

Wenn Sie das HTTP-Caching für Ihr /service-worker.js-Skript deaktiviert haben, indem Sie es mit Cache-Control: max-age=0 (oder einem ähnlichen Wert) bereitstellen, sollten Sie aufgrund des neuen Standardverhaltens keine Änderungen sehen.

Wenn Sie das Skript /service-worker.js mit aktiviertem HTTP-Caching bereitstellen, entweder absichtlich oder weil es nur der Standard für Ihre Hosting-Umgebung ist, sehen Sie möglicherweise einen Anstieg zusätzlicher HTTP-Anfragen für /service-worker.js an Ihren Server. Das sind Anfragen, die früher vom HTTP-Cache verarbeitet wurden. Wenn Sie weiterhin zulassen möchten, dass der Headerwert Cache-Control die Aktualität Ihrer /service-worker.js beeinflusst, müssen Sie bei der Registrierung Ihres Service Workers explizit updateViaCache: 'all' festlegen.

Angesichts der Tatsache, dass es viele Nutzer älterer Browserversionen geben kann, ist es dennoch sinnvoll, den HTTP-Header Cache-Control: max-age=0 weiterhin für Service Worker-Skripts festzulegen, auch wenn neue Browser sie möglicherweise ignorieren.

Entwickler können bei dieser Gelegenheit entscheiden, ob sie das HTTP-Caching für ihre importierten Skripts jetzt explizit deaktivieren und gegebenenfalls ihrer Service Worker-Registrierung updateViaCache: 'none' hinzufügen möchten.

Importierte Skripts bereitstellen

Ab Chrome 78 sehen Entwickler möglicherweise mehr eingehende HTTP-Anfragen für Ressourcen, die über importScripts() geladen werden, da diese jetzt auf Updates geprüft werden.

Wenn Sie diesen zusätzlichen HTTP-Traffic vermeiden möchten, legen Sie beim Bereitstellen von Skripts, die semver oder Hashes in ihren URLs enthalten, langlebige Cache-Control-Header fest und nutzen Sie das Standardverhalten updateViaCache von 'imports'.

Wenn Sie dagegen möchten, dass die importierten Skripts auf häufige Updates geprüft werden, stellen Sie sie entweder mit Cache-Control: max-age=0 bereit oder verwenden Sie updateViaCache: 'none'.

Weitere Informationen

Die Lesematerialien The Service Worker Lifecycle und Caching Best Practices und Max-age-Katchas von Jake Archibald werden allen Entwicklern empfohlen, die etwas im Web bereitstellen.