Aktuellere Service-Worker (Standard)

Kurzfassung

Ab Chrome 68 werden HTTP-Anfragen, die nach Updates des Service Worker-Scripts suchen, standardmäßig nicht mehr vom HTTP-Cache erfüllt. So wird ein häufiges Problem von Entwicklern umgangen, bei dem das versehentliche Setzen eines Cache-Control-Headers in Ihrem Service Worker-Script zu verzögerten Updates führen kann.

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

Ab Chrome 78 wird der Byte-für-Byte-Vergleich außerdem auf Scripts angewendet, die über importScripts() in einen Service Worker geladen werden. Jede Änderung an einem importierten Script löst den Ablauf zum Aktualisieren des Dienstarbeiters aus, genau wie eine Änderung am Dienstarbeiter der obersten Ebene.

Hintergrund

Jedes Mal, wenn Sie eine neue Seite aufrufen, die sich im Bereich eines Service Workers befindet, rufen Sie registration.update() explizit aus JavaScript auf. Wenn ein Service Worker über ein push- oder sync-Ereignis „geweckt“ wird, fordert der Browser parallel die JavaScript-Ressource an, die ursprünglich an den navigator.serviceWorker.register()-Aufruf übergeben wurde, um nach Updates für das Service Worker-Script zu suchen.

Angenommen, die URL lautet /service-worker.js und enthält einen einzelnen Aufruf von importScripts(), über den 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 wurde die Aktualisierungsanfrage für /service-worker.js wie die meisten Abrufe über den HTTP-Cache gesendet. Wenn das Script ursprünglich mit Cache-Control: max-age=600 gesendet wurde, wurden Updates innerhalb der nächsten 600 Sekunden (10 Minuten) nicht an das Netzwerk gesendet. Der Nutzer erhielt daher möglicherweise nicht die neueste Version des Service Workers. Wenn max-age jedoch größer als 86.400 (24 Stunden) ist, wird es so behandelt, als wäre es 86.400, damit Nutzer nicht für immer an einer bestimmten Version festhängen.

Ab Version 68 wird der HTTP-Cache ignoriert, wenn Updates für das Service Worker-Script angefordert werden. Daher kann es bei bestehenden Webanwendungen zu einer Häufung von Anfragen für das Service Worker-Script kommen. Anfragen für importScripts werden weiterhin über den HTTP-Cache gesendet. Das ist aber nur die Standardeinstellung. Mit der neuen Registrierungsoption updateViaCache können Sie dieses Verhalten steuern.

updateViaCache

Entwickler können beim Aufrufen von navigator.serviceWorker.register() jetzt eine neue Option übergeben: den updateViaCache-Parameter. Er kann einen der drei Werte haben: 'imports', 'all' oder 'none'.

Die Werte bestimmen, ob und wie der standardmäßige HTTP-Cache des Browsers bei der HTTP-Anfrage zum Prüfen auf aktualisierte Service Worker-Ressourcen verwendet wird.

  • Wenn 'imports' festgelegt ist, wird der HTTP-Cache nie bei der Suche nach Updates für das /service-worker.js-Script konsultiert, aber beim Abrufen importierter Scripts (path/to/import.js in unserem Beispiel). Das 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-Script der obersten Ebene als auch für alle Scripts abgerufen, die in den Dienstworker importiert wurden, z. B. path/to/import.js. Diese Option entspricht dem bisherigen Verhalten in Chrome vor Chrome 68.

  • Wenn 'none' festgelegt ist, wird der HTTP-Cache nicht bei Anfragen an die /service-worker.js der obersten Ebene oder an importierte Scripts wie das hypothetische path/to/import.js konsultiert.

Mit dem folgenden Code wird beispielsweise ein Dienstarbeiter registriert und sichergestellt, dass der HTTP-Cache nie konsultiert wird, wenn nach Aktualisierungen des /service-worker.js-Scripts oder anderer Scripts 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.
  });
}

Prüft, ob Updates für importierte Scripts verfügbar sind

Vor Chrome 78 wurde jedes über importScripts() geladene Service Worker-Script nur einmal abgerufen. Dabei wurde es je nach updateViaCache-Konfiguration zuerst im HTTP-Cache oder über das Netzwerk geprüft. Nach diesem ersten Abruf wird sie intern vom Browser gespeichert und nie wieder abgerufen.

Die einzige Möglichkeit, einen bereits installierten Dienst-Worker dazu zu zwingen, Änderungen an einem importierten Script zu übernehmen, war, die URL des Scripts zu ändern. Normalerweise wurde dazu entweder ein SemVer-Wert (z. B. importScripts('https://example.com/v1.1.0/index.js')) oder ein Hash des Inhalts (z. B. importScripts('https://example.com/index.abcd1234.js')) hinzugefügt. Ein Nebeneffekt der Änderung der importierten URL ist, dass sich der Inhalt des Dienst-Worker-Scripts der obersten Ebene ändert, was wiederum den Ablauf zum Aktualisieren des Dienst-Workers auslöst.

Ab Chrome 78 wird jedes Mal, wenn eine Aktualisierungsüberprüfung für eine Service Worker-Datei auf oberster Ebene durchgeführt wird, gleichzeitig geprüft, ob sich der Inhalt der importierten Scripts geändert hat. Je nach verwendeten Cache-Control-Headern werden diese importierten Scriptprüfungen möglicherweise vom HTTP-Cache ausgeführt, wenn updateViaCache auf 'all' oder 'imports' (Standardwert) festgelegt ist. Andernfalls werden die Prüfungen möglicherweise direkt an das Netzwerk gesendet, wenn updateViaCache auf 'none' festgelegt ist.

Wenn bei einer Aktualisierungsüberprüfung für ein importiertes Script ein Byte-für-Byte-Unterschied zum zuvor vom Dienst-Worker gespeicherten Inhalt festgestellt wird, wird der vollständige Aktualisierungsablauf für den Dienst-Worker ausgelöst, auch wenn die Dienst-Worker-Datei der obersten Ebene unverändert bleibt.

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

Was müssen Entwickler tun?

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

Wenn du dein /service-worker.js-Script mit aktiviertem HTTP-Caching auslieferst, entweder absichtlich oder weil es die Standardeinstellung für deine Hostingumgebung ist, kann es zu einem Anstieg der zusätzlichen HTTP-Anfragen für /service-worker.js an deinen Server kommen. Das sind Anfragen, die früher über den HTTP-Cache erfüllt wurden. Wenn Sie weiterhin zulassen möchten, dass der Cache-Control-Headerwert die Aktualität Ihrer /service-worker.js beeinflusst, müssen Sie updateViaCache: 'all' bei der Registrierung Ihres Service Workers explizit festlegen.

Da es möglicherweise viele Nutzer mit älteren Browserversionen gibt, sollten Sie den Cache-Control: max-age=0-HTTP-Header weiterhin in Service Worker-Scripts festlegen, auch wenn neuere Browser ihn möglicherweise ignorieren.

Entwickler können jetzt entscheiden, ob sie das HTTP-Caching für ihre importierten Scripts explizit deaktivieren möchten, und gegebenenfalls updateViaCache: 'none' in ihre Service Worker-Registrierung aufnehmen.

Importierte Scripts bereitstellen

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

Wenn Sie diesen zusätzlichen HTTP-Traffic vermeiden möchten, legen Sie langlebige Cache-Control-Header fest, wenn Sie Scripts ausliefern, deren URLs semver oder Hashes enthalten, und verlassen Sie sich auf das standardmäßige updateViaCache-Verhalten von 'imports'.

Wenn Sie möchten, dass Ihre importierten Scripts regelmäßig auf Updates geprüft werden, müssen Sie sie entweder mit Cache-Control: max-age=0 oder updateViaCache: 'none' ausliefern.

Weitere Informationen

The Service Worker Lifecycle“ und Caching Best Practices & Max-Age Gotchas von Jake Archibald sind empfehlenswerte Lektüre für alle Entwickler, die Inhalte im Web bereitstellen.