Aktuellere Service-Worker (Standard)

tl;dr

Ab Chrome 68 werden HTTP-Anfragen, die nach Aktualisierungen des Service Worker-Skripts suchen, nicht mehr standardmäßig vom HTTP-Cache ausgeführt. Dadurch lässt sich ein häufiges Entwicklerproblem umgehen, bei dem das Festlegen eines unbeabsichtigten Cache-Control-Headers in Ihrem Service Worker-Skript zu Verzögerungen bei Aktualisierungen führen kann.

Wenn Sie das HTTP-Caching für Ihr /service-worker.js-Skript bereits durch Bereitstellung mit Cache-Control: max-age=0 deaktiviert 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 in einem Service Worker über importScripts() 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 im Bereich eines Service Workers aufrufen, registration.update() explizit aus JavaScript aufrufen oder wenn ein Service Worker über ein push- oder sync-Ereignis "aufgeweckt" wird, fordert der Browser parallel 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 gehen wir davon aus, dass die URL /service-worker.js lautet und ein einzelner Aufruf von importScripts() enthält, mit dem zusätzlicher Code geladen wird, der im Service Worker 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 erfolgte die Aktualisierungsanfrage für /service-worker.js wie die meisten Abrufe über den HTTP-Cache. Wenn das Skript also ursprünglich mit Cache-Control: max-age=600 gesendet wurde, wurden innerhalb der nächsten 600 Sekunden (10 Minuten) keine Aktualisierungen an das Netzwerk gesendet, 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) ist, wird es so behandelt, als wäre 86.400, damit Nutzer nicht dauerhaft an eine bestimmte Version gebunden sind.

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 mehr Anfragen an ihr Service Worker-Skript kommen. Anfragen für importScripts werden weiterhin über den HTTP-Cache geleitet. Dies ist jedoch nur die Standardeinstellung. Es ist eine neue Registrierungsoption, updateViaCache verfügbar, die dieses Verhalten steuern kann.

updateViaCache

Entwickler können jetzt beim Aufrufen von navigator.serviceWorker.register() eine neue Option übergeben: den Parameter updateViaCache. Hierfür sind drei Werte zulässig: 'imports', 'all' oder 'none'.

Die Werte bestimmen, ob und wie der standardmäßige HTTP-Cache des Browsers bei der HTTP-Anfrage zum Suchen nach aktualisierten Service Worker-Ressourcen ins Spiel kommt.

  • Wenn 'imports' festgelegt ist, wird der HTTP-Cache bei der Suche nach Aktualisierungen für das Skript /service-worker.js nie geprüft. Beim Abrufen importierter Skripts (in unserem Beispiel path/to/import.js) wird jedoch eine Abfrage ausgeführt. Dies ist die Standardeinstellung und entspricht dem Verhalten ab Chrome 68.

  • Wenn 'all' festgelegt ist, wird der HTTP-Cache bei Anfragen sowohl für das /service-worker.js-Skript der obersten Ebene als auch für alle in den Dienst-Worker importierten Skripts, z. B. path/to/import.js, herangezogen. Diese Option entspricht dem Verhalten in Chrome vor Chrome 68.

  • Wenn 'none' festgelegt ist, wird der HTTP-Cache bei Anfragen für die übergeordnete /service-worker.js oder für importierte Skripts, wie das hypothetische path/to/import.js, nicht berücksichtigt.

Mit dem folgenden Code wird beispielsweise ein Service Worker registriert und der HTTP-Cache niemals aufgerufen, wenn nach Aktualisierungen für das Skript /service-worker.js oder für Skripts gesucht wird, auf die in /service-worker.js über importScripts() verwiesen wird:

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

Sucht nach Aktualisierungen für importierte Skripts

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

Die einzige Möglichkeit, einen bereits installierten Service Worker dazu zu zwingen, Änderungen an einem importierten Skript zu übernehmen, bestand darin, die URL des Skripts zu ändern. Dies geschieht in der Regel durch Hinzufügen eines semver-Werts (z. B. importScripts('https://example.com/v1.1.0/index.js')) oder durch Einfügen eines Hashs des Inhalts (z. B. importScripts('https://example.com/index.abcd1234.js')). Ein Nebeneffekt der Änderung der importierten URL besteht darin, dass sich der Inhalt des Service Worker-Skripts der obersten Ebene ändert, was wiederum den Aktualisierungsablauf auslöst.

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

Wenn eine 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 dieser Vorgang wiederum den vollständigen Service-Worker-Aktualisierungsablauf aus, auch wenn die Service-Worker-Datei der obersten Ebene gleich bleibt.

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

Was müssen Entwickler tun?

Wenn Sie das HTTP-Caching für Ihr /service-worker.js-Skript durch Bereitstellung mit Cache-Control: max-age=0 (oder einem ähnlichen Wert) effektiv deaktiviert haben, 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 Standardwert für Ihre Hostingumgebung ist, werden möglicherweise zusätzliche HTTP-Anfragen für /service-worker.js an Ihren Server gesendet. Dies sind Anfragen, die bisher vom HTTP-Cache ausgeführt wurden. Wenn Sie weiterhin zulassen möchten, dass der Headerwert Cache-Control die Aktualität von /service-worker.js beeinflusst, müssen Sie bei der Registrierung Ihres Service Workers explizit updateViaCache: 'all' festlegen.

Da es viele Nutzer mit älteren Browserversionen gibt, ist es trotzdem eine gute Idee, den Cache-Control: max-age=0-HTTP-Header in Service Worker-Skripts weiterhin festzulegen, auch wenn neue Browser ihn möglicherweise ignorieren.

Entwickler können diese Gelegenheit nutzen, um zu entscheiden, ob sie ihre importierten Skripts jetzt explizit vom HTTP-Caching deaktivieren möchten und gegebenenfalls updateViaCache: 'none' ihrer Service Worker-Registrierung hinzufügen.

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 verwenden Sie das standardmäßige updateViaCache-Verhalten von 'imports'.

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

Weitere Informationen

The Service Worker Lifecycle“ und „Caching best practices & max-age gotchas“, beide von Jake Archibald, werden allen Entwicklern empfohlen, die etwas im Web bereitstellen.