Web Worker erlauben es, in JavaScript Code getrennt vom Hauptthread im Hintergrund auszuführen. Web Worker gibt es in drei Typen: Dedicated Workers, Shared Workers und Service Workers.
Der gewöhnliche Web Worker nennt sich Dedicated Worker.
Problem
Traditionell wurden JavaScript-Skripte von Browsern nur in einem einzigen Thread im Vordergrund ausgeführt. Dies führt zu Problemen, wenn aufwändiger Code verarbeitet werden soll, da dieser möglicherweise sehr lange läuft und damit in der Zwischenzeit die Interaktion des Benutzers mit der Internetseite erschwert oder ganz unmöglich macht. Daher bieten die meisten Browser eine Möglichkeit ein lange laufendes Skript abzubrechen. Doch auch in diesem Fall kann der Browser für kurze Zeit durch ein Skript blockiert werden, zudem bereitet das Zeitlimit Skripten ein Problem, wenn diese eine komplexe und damit rechenintensive Aufgabe bearbeiten sollen. Um diesen Problemen zu begegnen, wurde die Web-Worker-API entwickelt.[1]
Web-Worker-API
Über newWorker('skript.js') kann ein neuer Web Worker eingerichtet werden. Der Browser lädt dazu das angegebene Skript in einen neuen Thread. Die Kommunikation mit dem Worker kann in beide Richtungen über die Methode postMessage und den Eventlisteneronmessage erfolgen.
Innerhalb des Workers stehen alle JavaScript-Funktionen zur Verfügung, die im ECMAScript-Standard definiert sind, ebenso viele der browsertypischen APIs. Eine wichtige Ausnahme hiervon ist das Document Object Model. Der Worker-Code hat hierauf keinen Zugriff und muss zum Verändern der Seite daher dem Hauptthread eine Nachricht schicken, damit dieser die gewünschten Befehle ausführt.
Variablenübergabe
Über postMessage können Variablen von einfachen Typen übergeben werden, Zahlen, Zeichenketten, Arrays und einfache Objekte (etwas mehr als in JSON möglich ist). Anders als bei Übergaben an Funktionen wird dabei eine Kopie angefertigt, die Daten also als Wertparameter und nicht wie sonst üblich als Referenzparameter übergeben. Funktionen und Objekte im Sinne von objektorientiertem Code müssen dagegen für eine Übergabe geeignet serialisiert und deserialisiert werden.
Binäre Daten können als ArrayBuffer übergeben werden, anschließend ist aber kein Zugriff mehr auf das Original möglich. Alternativ kann ein SharedArrayBuffer verwendet werden, der von mehreren Threads gleichzeitig bearbeitet werden kann. Hierfür stehen besondere atomare Operationen zur Verfügung.[2]
Während DOM-Elemente nicht an einen anderen Thread übergeben werden können, soll dies für Canvas-Elemente bis zu einem gewissen Maß möglich gemacht werden. Der Hauptthread kann über ein OffscreenCanvas-Element die Kontrolle an einen Hintergrundthread abgeben, dort können alle üblichen Funktionen zum Zeichnen aufgerufen werden.[3]
Beispiel
Das folgende Beispiel sucht nach Primzahlen. Diese werden der Reihe nach in einem Worker berechnet und dem Hauptthread zur Anzeige übergeben.[4]
Das HTML-Dokument bettet dabei direkt das Hauptskript ein. Dieses erstellt einen Worker und reagiert anschließend auf Mitteilungen, die dieser Worker sendet.
<!DOCTYPE html><html><head><title>Worker-Beispiel</title></head><body><p>Die bis jetzt größte gefundene Primzahl ist: <outputid="result"></output></p><script>varworker=newWorker('worker.js');// erzeugt neuen Workerworker.onmessage=function(event){// wird aufgerufen, wenn Worker eine Nachricht sendetdocument.getElementById('result').textContent=event.data;// zeigt die gefundene Primzahl an};</script></body></html>
Der Code für das Skript worker.js sucht dabei in einer Endlosschleife nach Primzahlen und teilt dem Hauptthread immer mit, wenn er eine gefunden hat:
vari,n=1;search:while(true){n++;for(i=2;i<=Math.sqrt(n);i++){if(n%i===0){continuesearch;}}// n ist eine PrimzahlpostMessage(n);}
Shared Worker
Ein gewöhnlicher Worker gehört immer zu der Seite, die ihn erzeugt hat. Ruft ein Benutzer die Seite mehrfach in seinem Browser auf (oder verschiedene Seiten derselben Domain, die den gleichen Worker einsetzen), so werden mehrere Worker mit dem gleichen Code initialisiert. Setzt man stattdessen einen SharedWorker ein, so wird dieser wiederverwendet.
Eine weitere besondere Art eines Web Workers ist der Service Worker. Dieser wird für zwei Aufgaben eingesetzt: Zum einen kann er als Proxy fungieren, zum anderen vom Server gesendete Benachrichtigungen selbst dann empfangen, wenn gerade keine Seite der entsprechenden Domain geöffnet ist.[5]
Für die Aufgabe als Proxy steht im Worker das fetch-Event zur Verfügung, das immer ausgelöst wird, wenn der Browser Daten der überwachten Domain anfordert, unabhängig davon, ob dies durch AJAX, Benutzernavigation oder andere Ursachen ausgelöst wird. Der Worker kann das Event abfangen und bei Bedarf die angeforderten Daten auf andere Weise zur Verfügung stellen. Insbesondere sind Service Worker als Ersatz für Application Cache zur Implementierung von Web-Apps vorgesehen, die auch offline funktionieren sollen.[6] Die Spezifikation ist aber so flexibel, dass zahlreiche weitere Möglichkeiten über einen einfachen Cache hinaus möglich sind.[7]
Browserunterstützung
Alle gängigen Browser bieten zumindest grundlegende Unterstützung für Web Worker, Mozilla Firefox ab Version 3.5, Google Chrome ab der Version 4, der Internet Explorer ab Version 10, Edge ab Version 12.[8] Die Unterstützung wurde und wird mit neueren Versionen immer weiter ausgebaut. So stehen Service Worker in Firefox ab Version 44, in Chrome ab Version 40 zur Verfügung und sind auch in diesen Browsern noch nicht im kompletten Umfang implementiert.[9]
Normen und Standards
Web Workers ist standardisiert vom W3C. Die aktuelle Spezifikation stammt vom 24. September 2015.
Web Workers – Link auf die aktuelle Spezifikation.