Denis Potschien 21. August 2015

Service Worker: JavaScript unabhängig von einer Website ausführen

Denis Potschien ist seit 2005 freiberuflich als Kommunikationsdesigner tätig, seit Anfang 2010...

Neue JavaScript-APIs haben in den letzten Jahren viele neue und nützliche Funktionen hervorgebracht, die vor allem für das mobile Web entwickelt wurden – zum Beispiel die Geolocation-der Application-Cache-API. Von den technischen Möglichkeiten nähern sich Webanwendungen immer mehr nativen Apps für Mobilgeräte an. Eine Sache war bislang jedoch den Apps vorbehalten: Anders als Webanwendungen können Apps auch dann laufen, wenn sie gar nicht geöffnet sind. Mit der neuen Service-Worker-API klappt das nun auch mit JavaScript und somit in Webanwendungen.

serviceworker-teaser_DE

Die Möglichkeiten der Service-Worker-API

Damit JavaScript ausgeführt werden kann, war es bislang immer Voraussetzung, dass eine Website in einem Browser geöffnet war. Mit dem Schließen einer Website – durch Schließen des Browser-Tabs oder -Fensters – wurden auch sämtliche ausgeführten JavaScripts beendet. Die neue Service-Worker-API hingegen erlaubt es, eine JavaScript-Datei auch dann auszuführen, wenn die dazugehörige Website gar nicht geöffnet ist.

Mit Service Workern ist es somit also möglich, Funktionen im Hintergrund auszuführen – auch nach dem Verlassen einer Website. Eine der Einsatzmöglichkeiten der Servive Worker ist das Cachen von Dateien im Hintergrund. Gerade bei der mobilen Nutzung der Internets sind Übertragsungsraten nicht immer gleich gut. Ein Service-Worker-Script hat die Möglichkeit, im Hintergrund neue Inhalte zu laden – bei einer Nachrichtenseite zum Beispiel neue Artikel samt Bilder. Wird die Nachrichtenseite zu einem späteren Zeitpunkt aufgerufen, stehen die Inhalte bereits zur Verfügung.

Die Voraussetzungen

Da die API noch recht neu ist, ist Chrome derzeit der einzige Browser, der die API gut unterstützt und auch Debugging-Möglichkeiten zur Verfügung stellt. Im Firefox lassen sich Servive Worker für Nightly-Builds über „about:config“ aktivieren. Andere Browser unterstützen die API derzeit noch nicht.

Außerdem funktionieren Service Worker ausschließlich über sichere HTTPS-Verbindungen. Das hat in erster Linie Sicherheitsgründe. Denn mit einem im Hintergrund laufenden Service-Worker-Script lässt sich eine Website kontrollieren. Aber es ist ohnehin damit zu rechnen, dass neue APIs, die Zugriff auf sensible Funktionen oder Hardware haben, ausschließlich über HTTPS-Verbindungen laufen werden.

Servive Worker registrieren

Wie bereits erwähnt, handelt es sich bei einem Service Worker um eine von der eigentlichen Website losgelöste JavaScript-Datei, die im Hintergrund – unsichtbar für den Besucher – ausgeführt wird. Diese JavaScript-Datei muss zunächst im Browser registriert werden. Dies geschieht über die „register()“-Methode der Service-Worker-API.

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("service-worker.js").then(
    function(erfolg) {
      console.log("Ja, hat geklappt.", erfolg);
    }
  ).catch(
    function(fehler) {
      console.log("Nein, hat leider nicht geklappt.", fehler);
    }
  );
}

Im Beispiel wird zunächst über eine „if“-Abfrage geprüft, ob der Browser die Service-Worker-API überhaupt unterstützt. Anschließend wird die Datei „service-worker.js“ registriert. Über einen Promise – „then()“ beziehungsweise „catch()“ – wird in der Konsole ausgegeben, ob die Registrierung geklappt hat oder nicht. Versucht man beispielsweise einen Service Worker über eine nicht sichere HTTP-Verbindung zu registrieren, wird der Browser die Registrierung ablehnen und die Fehlermeldung der „catch()“-Methode ausgeben.

Die Service-Worker-Datei hat ab dem Zeitpunkt der Registrierung die Möglichkeit, den Inhalt der Website zu verändern. Allerdings kann man den Zugriff auf bestimmte Verzeichnisse der Website begrenzen. Hierzu wird per „scope“ ein Verzeichnis übergeben.

navigator.serviceWorker.register("service-worker.js", {
  scope: "/verzeichnis/"
})

Im Beispiel hätte das Service-Worker-Script nur Zugriff auf die Inhalte des angegebenen Verzeichnisses – einschließlich seiner Unterverzeichnisse.

Mit Service Workern arbeiten

Nachdem der Service Worker registriert wurde, nimmt das Script – im Beispiel die Datei „service-worker.js“ seine Arbeit auf. Es wird nun vom Browser im Hintergrund ausgeführt. Sobald die Website, über welche der Service Worker registriert wurde, neu geladen wird, hat der Service Worker Zugriff auf die Website und kann die Ausgabe der Website beeinflussen.

Innerhalb der Service-Worker-Datei steht einem nun das „fetch“-Event zur Verfügung. Das „fetch“-Event wird immer dann gestartet, wenn eine Ressource innerhalb des per „scope“ definierten Bereiches abgerufen wurde. Es erlaubt einem, mit der Methode „respondWith()“ mit der Seite zu kommunizieren und einzelne Requests zu überschreiben. Dazu wird ein neuer Response erstellt und der alte dadurch ersetzt.

self.addEventListener("fetch", function(e) {
  e.respondWith(new Response("Das ist ein neuer Inhalt"));
});

Das einfache Beispiel sorgt dafür, dass jeder Request innerhalb des „scope“-Verzeichnisses – sei es ein HTML-Dokument oder eine Grafik – mit dem neuen Response überschrieben wird. Auch komplexe Responses sind möglich. Mit der zusätzlichen Option „headers“ kann man weitere Angaben zur Art des Responses machen.

e.respondWith(new Response("<svg>…</svg>", {
   headers: {
     "Content-Type": "image/svg+xml"
   }
 }));

Im Beispiel eine SVG-Grafik mit entsprechendem Content-Type ausgegeben.

Inhalte laden und an bestimmte Requests ausgeben

Statt mit „Response()“ eigene Inhalte zu bauen, mit denen man bestehende Inhalte überschreibt, hat man auch die Möglichkeit, mit der „fetch()“-Methode Inhalte zu laden.

e.respondWith(
  fetch("https://www.example.com/bild.jpg", {
    mode: "no-cors"
  })
);

Im Beispiel wird von einer externen Domain eine Bilddatei geladen. Die Angabe von „no-cors“ über die Option „mode“ ist notwendig, um das Laden von Inhalten aus externen Quellen zu erlauben.

In den bisherigen Beispielen sind mit „respondWidth()“ immer alle Requests – HTML-Dokumente, Bilder und alles andere, was über eine URL ausgegeben wird – überschrieben worden. Das will man in der Regel natürlich nicht erreichen. Über einfache „if“-Abfragen kann man jedoch bestimmte URLs mit einem eigenen Response überschreiben.

if (e.request.url.indexOf(".jpg") >= 0) {
  e.respondWith(
    fetch("https://www.example.com/bild.jpg", {
      mode: "no-cors"
    })
  );
}

Im Beispiel werden alle Requests, welche die Zeichenkette „.jpg“ beinhalten, mit der extern geladenen Datei „bild.jpg“ überschrieben. Alle anderen Requests bleiben unberührt und geben ihre Inhalte in gewohnter Weise aus.

Debugging im Chrome

Eine Übersicht aller im Browser registrierten Service Worker erhält man über die Eingabe von „chrome://inspect/#service-workers“ in der Adressleiste des Chrome-Browsers. Für jeden Service Worker stehen die Funktionen „inspect“ und „terminate“ zur Verfügung. Chrome vergibt für jeden Service Worker eine Prozess-ID („pid“), die vor der URL des Service-Worker-Scripts angegeben wird. Per „inspect“ wird ein Fenster mit den „Developer Tools“ von Chrome geöffnet. Dort stehen einem die bekannten Debugging-Funktionen zur Verfügung.

serviceworker_chrome
Registrierte Service Worker im Chrime

Über den Punkt „terminate“ wird der jeweilige Service Worker wieder gelöscht.

Cashing mit Service Workern

Die Service Worker sind mit einer eigenen Caching-Funktion ausgestattet, die unabhängig vom „Application Cache“ der HTML5-Caching-API läuft. Über den Service-Worker-Cache lassen sich Dateien, die beispielsweise als Teil einer Webanwendung verfügbar gemacht werden sollen, im Hintergrund herunterladen – auch wenn die Seite zwischenzeitlich verlassen wird.

serviceworker_chrome-dev-tools
„Developer Tools“ für einen Service Worker – mit dem Service-Worker-Cache

Das Cachen von Dateien lässt sich über das „install“-Event der Servive-Worker-API realisieren. Dieses wird nach der Registrierung aufgerufen.

self.addEventListener("install", function(e) {
  e.waitUntil(
    caches.open("mein-cache").then(function(cache) {
      return cache.addAll([
        "webapp.js",
        "webapp.css",
        "wabapp.png"
      ]);
    })
  );
});

Die Methode „waitUntil()“ sorgt dafür, dass andere Events erst gestartet werden, wenn das aktuell laufende beendet wurde. So wird sichergestellt, dass zum Beispiel das „fetch“-Event erst gestartet wird, wenn alle Dateien innerhalb des „install“-Events gecached wurden.

Per „cache.open()“ wird ein Servive-Worker-Cache angelegt. Diesem wird ein individueller Name – im Beispiel „mein-cache“ – gegeben. Anschließend werden per „addAll()“ die Dateien übergeben, die dem Cache hinzugefügt werden sollen.

Da Chrome die Methode „addCache()“ derzeit noch nicht unterstützt, ist ein Polyfill notwendig, welches diese Funktionalität nachrüstet. Anschließend stehen die gecachten Dateien zur Verfügung und werden anstelle der Dateien auf dem Server verwendet. Anders als normaler Cache wird nicht geprüft, ob aktuellere Dateien zur Verfügung stehen.

Fazit

Auch wenn sich die Service-Worker-API derzeit aufgrund der beschränkten Browserunterstützung noch nicht produktiv einsetzen lässt, hat sie viel Potenzial, um gerade Webapps für das mobile Internet schneller und komfortabler zu machen.

Denis Potschien

Denis Potschien ist seit 2005 freiberuflich als Kommunikationsdesigner tätig, seit Anfang 2010 im Kreativkonsulat in Iserlohn, einem Büro für Gestaltung und Kommunikation. Dort betreut er kleine und mittelständische Unternehmen ebenso wie kommunale Körperschaften und Organisationen aus Südwestfalen und dem Ruhrgebiet. Als Webdesigner und -entwickler gehören HTML5 und CSS3 zu seinen Kernthemen, weshalb er dazu 2013 ein Buch geschrieben hat. „Pure HTML5 und CSS3“ richtet sich an alle, die Vorkenntnisse haben, sich aber bisher mit HTML5 und CSS3 nicht oder nur am Rande beschäftigt haben.

Kennst du schon unseren Newsletter?

Hinweise zum Datenschutz, also dem Einsatz von Double-Opt-In, der Protokollierung der Anmeldung, der Erfolgsmessung, dem Einsatz von MailChimp als Versanddienstleister und deinen Widerrufsrechten findest du in unseren Datenschutzhinweisen.

Cookies

Weitere Informationen zu den Auswahlmöglichkeiten findest du hier. Dazu musst du zunächst keine Auswahl treffen!

Um Dr. Web zu besuchen, musst du eine Auswahl treffen.

Deine Auswahl wurde gespeichert!

Informationen zu den Auswahlmöglichkeiten

Was du erlaubst!

Um fortfahren zu können, musst du eine Auswahl treffen. Nachfolgend erhältst du eine Erläuterung der verschiedenen Optionen und ihrer Bedeutung.

  • Ich stimme zu:
    Du erlaubst uns das Setzen aller Cookies, die wir in unseren Datenschutzhinweisen genannt haben. Dazu gehören Tracking- und Statistik-Cookies. Aus dem Tracking per Google Analytics bieten wir auf der Seite Datenschutz ein Opt-Out, also die Möglichkeit der Abmeldung, an.
  • Ich stimme nicht zu:
    Wir verzichten bei dieser Option auf den Einsatz von Google Analytics. Die für den Betrieb von Dr. Web notwendigen Cookies werden aber dennoch gesetzt. Einzelheiten entnimmst du bitte den Datenschutzhinweisen

Du kannst deine Cookie-Einstellungen jederzeit hier ändern: Datenschutz. Impressum

Zurück