JavaScript/Objekte/ServiceWorkerGlobalScope

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Die Schnittstelle ServiceWorkerGlobalScope ist ein Teil des Serviceworker-API. Sie stellt eine Erweiterung der WorkerGlobalScope-Schnittstelle dar und beinhaltet damit auch das WindowOrWorkerGlobalScope-Mixin.

Das globale Objekt eines Serviceworkers ist ein ServiceWorkerGlobalScope-Objekt.

Beachten Sie: Das globale Objekt eines Workers finden Sie in den globalen Variablen self und globalThis. Ein window-Objekt gibt es in Workern nicht.

Außer den von WorkerGlobalScope und WindowOrWorkerGlobalScope übernommenen Eigenschaften, Methoden und Ereignissen bietet die ServiceWorkerGlobalScope-Schnittstelle noch folgendes an:

Eigenschaften
Von WorkerGlobalScope geerbt:

Von WindowOrWorkerGlobalScope hinzugefügt:

Eigene:

  • clients
  • registration
  • serviceWorker

Methoden
Von WorkerGlobalScope geerbt:

Von WindowOrWorkerGlobalScope hinzugefügt:

Eigene:

Auf Ereignisse auf ServiceWorkerGlobalScope zu reagieren ist die Hauptaufgabe eines Serviceworkers.

Eigenschaften[Bearbeiten]

clients
Kein Array, sondern ein Clients-Objekt, das Zugriff auf die aktiven Clients des Serviceworkers bietet.
registration
Enthält das ServiceWorkerRegistration-Objekt, das den in diesem Scope laufenden Serviceworker verwaltet.
serviceWorker
Enthält das ServiceWorker-Objekt, das in diesem Scope ausgeführt wird.
Prüfen Sie vor der Verwendung, ob die Eigenschaft vorhanden ist, Firefox unterstützt sie zur Zeit noch nicht.

Methoden[Bearbeiten]

skipWaiting()[Bearbeiten]

Diese Methode kann von einer Serviceworker-Instanz verwendet werden, die in der Registration noch als waiting eingetragen ist, um die active-Instanz zu verdrängen und selbst zum aktiven ServiceWorker zu werden.

Die Clients der bisher aktiven ServiceWorker-Instanz werden von diesem Wechsel durch ein controllerchange Event auf ihrem ServiceWorkerContainer-Objekt benachrichtigt. Überlegen Sie gut, ob Sie skipWaiting verwenden wollen. Der Austausch des aktiven ServiceWorkers kann zu kniffligen Problem führen, wenn Clients und Worker intensiv miteinander interagieren[1].

Ereignisse[Bearbeiten]

An dieser Stelle werden die Ereignisse nur grundsätzlich dargestellt. Beispiele für eine Realisierung finden Sie im App-Tutorial.

Wenn ein Serviceworker-Script geladen und ausgeführt wird, tut es nicht viel mehr, als einige Variablen zu initialisieren und Handler für die im Folgenden beschriebenen Ereignisse zu registrieren. Die eigentliche Arbeit des Workers findet in den Eventhandler-Funktionen dieser Ereignisse statt.

Wichtige Hinweise[Bearbeiten]

Beachten Sie: ein Serviceworker-Script kann jederzeit entladen und später neu gestartet werden. Sie können sich nicht darauf verlassen, dass ein Wert, den sie während einer Ereignisbehandlung in einer globalen Variablen ablegen, bei der Verarbeitung des nächsten Ereignisses noch vorhanden ist.

Alle Ereignisse, die auf dem ServiceWorkerGlobalScope ausgelöst werden, verwenden die Schnittstelle ExtendableEvent oder eine, die davon abgeleitet ist. Ein solches Ereignis ist nicht automatisch erledigt, wenn alle dafür registrierten Eventhandler-Funktionen enden, sondern es bleibt im Zustand active, bis alle in ihm registrierten Lifetime-Promises erfüllt wurden. Hinzu kommt, dass solche Events in dem Serviceworker gespeichert werden, für den sie ausgelöst wurden. Ein Serviceworker, der beendet werden soll, wartet damit so lange, bis er kein aktives ExtendableEvent mehr in seiner Liste hat. Bitte lesen Sie den Artikel zu ExtendableEvent für weitere Informationen.

Beachten Sie: ServiceWorker dürfen keine synchron arbeitenden APIs verwenden. Der ExtenableEvent-Mechanismus ist keine Option, sondern Pflicht, wenn Sie auf externe Ressourcen zugreifen.

install[Bearbeiten]

Typ des Ereignisobjekts: ExtendableEvent

Wenn ein Serviceworker-Script erstmalig oder als neue Version geladen wird, bekommt es mit dem install Event zunächst die Gelegenheit, sich zu initialisieren. Sobald dieses Event erfolgreich behandelt wurde, geht der initialisierte ServiceWorker in den waiting Zustand über.

Das Event ist erfolgreich behandelt, wenn keines seiner Lifetime-Promises, die Sie mit der waitUntil()-Methode registrieren können, mit einem Reject erfüllt wird. Es ist deshalb wichtig, dass Sie zurückgegebene Promises von asynchronen Methoden, die Sie im install-Eventhandler benötigen, mit waitUntil() am Ereignisobjekt registrieren.

Skelett eines install-Eventhandlers
const myCacheName = 'Selfcache-V1';
const offlineFiles = [ 'index.html', 'style.css', 'app.js', 'background.png' ];

self.addEventListener("install", (installEvent) => {
   installEvent.waitUntil(installHandler(installEvent));
});

function installHandler(installEvent) {
   return caches
          .open(myCacheName)
          .then(cache => cache.addAll(offlineFiles))
}
caches.open liefert ein Promise für einen konkreten Cache, und die addAll-Methode dieses Caches wiederum ein Promise, das sich erfüllt, sobald alle offline-Files geladen sind. Die then-Methode erzeugt wiederum ein Promise, dessen Erfüllung an das Promise von addAll gebunden ist. Heißt insgesammt: die installHandler gibt ein Promise zurück, das sich erfüllt, sobald der Cache befüllt ist.


Strukturen dieser Art sind für asynchrone Programmierschnittstellen, wie man sie in Workern oder auch in node.js findet, typisch.

Ein erfolgreich ausgeführtes Install-Event bringt den Serviceworker in den installed-Zustand. Im ServiceWorkerRegistration-Objekt findet er sich jetzt in der waiting Eigenschaft.

activate[Bearbeiten]

Typ des Ereignisobjekts: ExtendableEvent

Der Serviceworker erhält das activate Event, sobald er zum aktiven ServiceWorker werden kann. Solange es für seine Registrierung noch keinen aktiven Serviceworker gibt, erfolgt das sofort nach dem install-Event. Andernfalls wartet der Browser mit dem activate-Event, bis der aktive Serviceworker keine Clients mehr hat, oder der wartende Serviceworker die Aktivierung mittels skipWaiting() erzwingt.

Der activate-Eventhandler hat die Aufgabe, den Übergang zwischen Serviceworker-Versionen zu steuern. Dazu kann gehören: - den Cache der Offlinedateien neu zu laden - Daten, die von der vorherigen Version erstellt wurden, umzuspeichern - Daten, die die vorherige Version hinterlassen hat, zu entfernen

Die korrekte Datenübernahme bei Softwareupdates ist etwas, das man sehr genau planen muss. Es ist beispielsweise nicht gewährleistet, dass die Version 17 Ihres Serviceworkers die Version 16 ersetzt. Wenn der Computer zuvor länger nicht genutzt wurde, kann es durchaus geschehen, dass die Version 17 die erste Version überhaupt ist, oder auch dass sie die Version 1 ersetzt.

Genau wie im install-Event kann es auch im activate-Event nötig sein, Methoden aufzurufen, die Promises zurückliefern. Verwenden Sie auch hier die waitUntil-Methode des Eventobjekts, um den Abschluss der Aktivierung hinauszuzögern, bis diese Promises erfüllt sind.

Beachten Sie: Ein Reject eines Lifetime-Promise des activate-Events führt nicht zum Abbruch der Aktivierung.

Dass ein Serviceworker aktiv wurde, bedeutet nicht, dass er automatisch allen potenziellen Clients (Webseiten und Webworker) zugeordnet wird, die in seiner Scope-URL liegen. Von allein geschieht das nur für Clients, die nach der Aktivierung des Serviceworkers geladen wurden. Sie können aber auch die claim()-Methode des Clients-Objekt verwenden, um bereits geladene Clients an den Serviceworker zu binden. Genau wie bei skipWaiting() erhalten die so angebundenen Clients ein controllerchanged Event, um auf die Zuordnung des Serviceworkers reagieren zu können.

fetch[Bearbeiten]

Typ des Ereignisobjekts: FetchEvent (abgeleitet von ExtendableEvent)

Sobald ein Client von einem Serviceworker kontrolliert wird, führt jedes Laden einer externen Ressource zu einem fetch-Event auf dem self-Objekt des Serviceworkers. Das fetchEvent-Objekt enthält den Request, der an den Server geschickt werden soll. Der Serviceworker kann daraufhin den Request aus dem Cache beantworten oder ihn mit Hilfe des fetch API an den Server weiterleiten. Beide Alternativen führen zu einem Promise, das zu einem Response-Objekt resolved wird, und das fetchEvent-Objekt stellt die Methode respondWith() bereit, um auf die Erfüllung dieses Promises zu warten und das erhaltene Response-Objekt an den Client zurückzugeben.

respondWith() verhält sich ähnlich wie waitUntil(), sie fügt das übergebene Promise der Liste von Lifetime-Promises des Fetch-Events hinzu. Der Unterschied ist, dass der Wert des an respondWith() übergebenen Promises zum Ergebnis des Fetch-Vorgangs beim Client wird. Aber beide haben gemeinsam, dass die Event-Behandlung erst abgeschlossen ist, wenn alle Lifetime-Promises erfüllt wurden. Weitere Lifetime-Promises können auch in einem fetch-Event sinnvoll sein: Wenn Sie zu einem Request keinen Eintrag im Cache finden, möchten Sie ihn vielleicht in den Cache legen, nachdem der Server die Response geliefert hat. Dieser Schreibvorgang in den Cache ist ebenfalls Promise-gesteuert, und Sie sollten dieses Promise mit waitUntil der Liste der Lifetime-Promises hinzufügen.

message[Bearbeiten]

Typ des Ereignisobjekts: ExtendableMessageEvent (abgeleitet von ExtendableEvent)

Dieses Ereignis wird ausgelöst, wenn der ServiceWorker eine Nachricht von einem seiner Clients erhält. Der Client ruft postMessage() auf dem ServiceWorker-Objekt auf, ausgelöst wird das Ereignis aber auf dem ServiceWorkerGlobalScope-Objekt.

Ein ExtendableMessageEvent ist eine Mischung aus einem normalen MessageEvent und einem ExtendableEvent. Sie finden die übermittelten Daten wie gewohnt in der Eigenschaft data, den Absender in source und seinen Origin in origin.

messageerror[Bearbeiten]

Typ des Ereignisobjekts: ExtendableMessageEvent (abgeleitet von ExtendableEvent)

Dieses Ereignis signalisiert, dass dem Serviceworker eine Nachricht geschickt wurde, diese aber nicht deserialisiert werden konnte. Näheres finden Sie bei der Beschreibung von MessageEvent.

Referenzen[Bearbeiten]

  1. Google Web Fundamentals: Serviceworkers Lifecycle