JavaScript/Tutorials/App/ServiceWorker

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Text-Info

Lesedauer
20min
Schwierigkeitsgrad
mittel
Vorausgesetztes Wissen
???


Ein Serviceworker ist ein JavaScript-Programm, das für die Netzwerkunabhängigkeit einer Progressiven Web-App unerlässlich ist. Serviceworker können in die Netzwerkzugriffe der Webseite, für die sie installiert wurden, eingreifen und sie beantworten, ohne dass die Webseite merkt, dass die Antwort nicht vom Server kam.

Ein Serviceworker ist eine Sonderform eines Webworkers. Genau wie dieser läuft ein Serviceworker unabhängig vom JavaScript-Kontext der Webseite und hat deshalb keinen Zugriff auf das DOM. Die Kommunikation zwischen Serviceworker und Webseiten erfolgt mittels postMessage, sofern sie erforderlich ist. Und im Gegensatz zu einem Webworker kann ein Serviceworker mehrere Webseiten gleichzeitig als Kommunikationspartner haben.

Voraussetzungen[Bearbeiten]

Serviceworker werden von Chrome, Chromium-Edge, Firefox, Opera und Safari unterstützt, auf Desktop-PCs, Android und iOS Geräten. Diese Aussage basiert auf den Angaben von caniuse.com. Browser, die von caniuse nicht gelistet werden, unterstützen Serviceworker möglicherweise trotzdem. Der Code, den wir zum Registrieren eines Serviceworkers zeigen werden, berücksichtigt das.

  • Chrome
  • Edge
  • Firefox
  • Opera
  • Safari

Details: caniuse.com

Um überhaupt einen Serviceworker installieren zu können, muss eine Seite über HTTPS ausgeliefert werden, denn Serviceworker sind Code, denen eine Website unbedingt vertrauen können muss, denn sie sind genauso Teil der Website wie der Frontend-Code. Auf Entwicklergeräten ist diese Restriktion hinderlich, deswegen kann ein Serviceworker von localhost auch über http installiert werden.

Registrieren eines Serviceworkers[Bearbeiten]

Sicherlich möchten Sie nun wissen, wie man einen solchen Serviceworker baut. Aber zunächst wollen wir beschreiben, wie man ihn mit der Webseite verknüpft.

Browser, die ServiceWorker unterstützen, bieten auf dem window.navigator Objekt die Eigenschaft serviceWorker an. Über diese Eigenschaft erhält man ein ServiceWorkerContainer Objekt, das die Methode register bereitstellt. Diese Methode arbeitet asynchron, d.h. sie liefert ein Promise zurück, das erfüllt wird, sobald der Worker erfolgreich geladen wurde.

Wenn Sie Schwierigkeiten haben, diesen Code grundsätzlich zu verstehen, dann bitten wir Sie um Verständnis. Serviceworker sind eine komplexe Materie, und wir müssen Grundkenntnisse in JavaScript voraussetzen. Je nach Verständnisschwierigkeit können wir folgende Wiki-Artikel anbieten:

Verständnisfragen können Sie natürlich gerne auch im Self-Forum stellen.

Installieren eines Serviceworkers
function registerServiceWorker() {
  if (document.readyState == 'complete') {
    return navigator.serviceWorker.register('/serviceworker.js');
  }

  return new Promise((resolve, reject) => {
    window.addEventListener("load", () =>
      navigator.serviceWorker.register('/serviceworker.js')
      .then(registration => resolve(registration))
      .catch(fehler => reject(fehler))
    );
  });
}

Folgende Dinge sind in dem gezeigten Codestück wichtig:

  • Die Funktion fragt nicht ab, ob der Browser Serviceworker unterstützt. Der Grund dafür ist, dass sich die Webseite in diesem Fall möglicherweise ganz anders verhalten sollte. Diese Steuerung sollte außerhalb der Registrierungsfunktion liegen.
  • Die Funktion gibt ein Promise zurück. Wer sie verwendet, kann über das Promise eine Rückmeldung erhalten, ob die Registrierung gelungen ist.
  • Die Funktion prüft, ob der readyState des Dokuments bereits auf 'complete' steht. Wenn ja, registriert sie den Serviceworker sofort und gibt das Promise zurück, das die register-Methode liefert, denn das load-Event ist in diesem Fall bereits vorbei. Diese Abfrage ist dann relevant, wenn die Registrierung des Serviceworkers nicht beim Laden der Seite ausgelöst wird, sondern erst später, bspw. durch eine Benutzerinteraktion.
  • Wenn das load Event noch bevorsteht, wird die eigentliche Registrierung in einem load-Eventhandler durchgeführt. Das load-Event ist der früheste sinnvolle Zeitpunkt, denn es wird eine Aufgabe des Serviceworkers sein, die wichtigsten Dateien für Ihre App auch offline bereitzustellen. Das bedeutet: wenn er sich registriert, muss er sie laden. Sie müssen vermeiden, dass dieser Ladevorgang das Laden der eigentlichen Webseite behindert, andernfalls laufen Ihnen die Anwender schon weg, bevor sie die Vorteile Ihrer PWA erleben können. Es ist nun nicht mehr möglich, das register-Promise direkt zurückzugeben, deswegen wird ein eigenes Promise erzeugt, das nichts weiter tut, als Erfolg oder Misserfolg von register weiterzureichen.

Benutzen kann man die Funktion dann so:

Aufruf der Registrierung
  if ('serviceWorker' in navigator) {
    registerServiceWorker()
    .catch(fehler => {
       // Fehlermeldung ausgeben, dass keine Registrierung möglich 
    })
  }  
  else {
    // alternative Steuerung für Browser ohne Serviceworker
  }

Scope eines Serviceworkers und Registrierungsoptionen[Bearbeiten]

Serviceworker werden grundsätzlich aus einer eigenen JavaScript-Datei geladen. Der URL für diese Datei kann absolut oder relativ sein, ein relativer URL ist relativ zur Adresse der HTML Seite, zu der das Registrierungsscript gehört.

Sofern Sie nichts anderes angeben, ist der URL-Pfad, aus dem die Serviceworker-Datei geladen wird, der Gültigkeitsbereich (Scope) dieses Serviceworkers. Das bedeutet, dass alle HTML Seiten, die aus diesem Pfad oder einem untergeordneten Pfad geladen werden, mit diesem Serviceworker verknüpft werden und seine Dienste in Anspruch nehmen können.

Sie können der register-Methode einen zweiten Parameter übergeben. Dabei handelt es sich um ein RegistrationOptions-Objekt, in dem Sie über die scope-Eigenschaft einen URL-Pfad für den Gültigkeitsbereich festlegen können. Dieser Scope-URL kann absolut oder relativ zum Pfad der HTML Seite sein. Näheres können Sie in der Referenz zu ServiceWorkerRegistration/register nachlesen.

Der Serviceworker[Bearbeiten]

tbd


Quellen[Bearbeiten]