Web Worker

Bisher ging es in diesem Kurs vor allem um Konzepte wie allgemeine HTML-Leistungsaspekte, Ressourcenhinweise, die Optimierung verschiedener Ressourcentypen zur Verbesserung der anfänglichen Seitenladezeit und Reaktionsfähigkeit auf Nutzereingaben sowie auf Lazy Loading bestimmter Ressourcen.

Es gibt jedoch einen Leistungsaspekt bei JavaScript, der in diesem Kurs noch nicht behandelt wurde. Dies ist die Rolle von Web Workern bei der Verbesserung der Reaktionsfähigkeit von Eingaben, die in diesem und im nächsten Modul behandelt wird.

JavaScript wird oft als Single-Threaded-Sprache beschrieben. In der Praxis bezieht sich dies auf den Hauptthread. Dabei handelt es sich um den einzelnen Thread, in dem der Browser die meiste Arbeit erledigt, die im Browser angezeigt wird. Dazu gehören Aufgaben wie Skripterstellung, einige Arten von Rendering, HTML- und CSS-Parsing und andere nutzerorientierte Aufgaben, die die Nutzererfahrung verbessern. In Wirklichkeit verwenden Browser andere Threads für Arbeiten, auf die Sie als Entwickler normalerweise keinen direkten Zugriff haben, z. B. GPU-Threads.

Bei JavaScript sind Sie in der Regel auf die Arbeit im Hauptthread beschränkt, allerdings nur standardmäßig. Es ist möglich, zusätzliche Threads in JavaScript zu registrieren und zu verwenden. Die Funktion, die Multithreading in JavaScript ermöglicht, wird als Web Workers API bezeichnet.

Web Worker sind nützlich, wenn Sie rechenintensive Arbeit haben, die einfach nicht im Hauptthread ausgeführt werden kann, ohne lange Aufgaben zu verursachen, die die Seite nicht mehr reagieren. Solche Aufgaben können sich auf jeden Fall auf die Interaction to Next Paint (INP) Ihrer Website auswirken. Daher kann es hilfreich sein zu wissen, wann Sie Aufgaben haben, die vollständig vom Hauptthread aus erledigt werden können. So schaffen Sie mehr Platz für andere Aufgaben im Hauptthread und Nutzer können schneller interagieren.

In diesem Modul und in der folgenden Demo mit einem konkreten Anwendungsfall werden Web-Worker behandelt. Die Demo selbst zeigt, wie Sie mit einem Web Worker Bildmetadaten aus einer JPEG-Datei aus dem Hauptthread lesen und wie Sie diese Metadaten an den Hauptthread zurückerhalten, damit der Nutzer sie sehen kann.

Einführung eines Web Workers

Ein Web Worker wird durch Instanziieren der Worker-Klasse registriert. Dabei geben Sie an, wo sich der Web-Worker-Code befindet, der vom Browser geladen wird, und erstellt anschließend einen neuen Thread. Der resultierende Thread wird häufig als Worker-Thread bezeichnet.

const myWebWorker = new Worker('/js/my-web-worker.js');

In der JavaScript-Datei des Workers – in diesem Fall my-web-worker.js – können Sie dann Code schreiben, der dann in einem separaten Worker-Thread ausgeführt wird.

Einschränkungen für Web Worker

Anders als bei JavaScript, das im Hauptthread ausgeführt wird, haben Web-Worker keinen direkten Zugriff auf den window-Kontext und nur eingeschränkten Zugriff auf die bereitgestellten APIs. Für Web-Worker gelten die folgenden Einschränkungen:

  • Web-Worker können nicht direkt auf das DOM zugreifen.
  • Web Worker können über eine Messaging-Pipeline mit dem window-Kontext kommunizieren. Das bedeutet, dass ein Web Worker indirekt auf das DOM zugreifen kann.
  • Der Web-Worker-Bereich ist self, nicht window.
  • Der Web-Worker-Bereich hat Zugriff auf JavaScript-Primitive und -Konstrukte, aber auch auf APIs wie fetch und eine große Anzahl anderer APIs.

So kommunizieren Web Worker mit den window

Ein Web Worker kann über eine Messaging-Pipeline mit dem window-Kontext des Hauptthreads kommunizieren. Mit dieser Pipeline können Sie Daten zum und vom Hauptthread und dem Web Worker übertragen. Zum Senden von Daten von einem Web-Worker an den Hauptthread richten Sie ein message-Ereignis für den Web-Worker-Kontext (self) ein.

// my-web-worker.js
self.addEventListener("message", () => {
  // Sends a message of "Hellow, window!" from the web worker:
  self.postMessage("Hello, window!");
});

Anschließend können Sie in einem Skript im window-Kontext des Hauptthreads die Nachricht aus dem Web-Worker-Thread mithilfe eines weiteren message-Ereignisses empfangen:

// scripts.js

// Creates the web worker:
const myWebWorker = new Worker('/js/my-web-worker.js');

// Adds an event listener on the web worker instance that listens for messages:
myWebWorker.addEventListener("message", ({ data }) => {
  // Echoes "Hello, window!" to the console from the worker.
  console.log(data);
});

Die Messaging-Pipeline des Web Workers ist eine Art Ausstieg aus dem Web-Worker-Kontext. Damit können Sie Daten vom Web Worker an den window senden, mit denen Sie das DOM aktualisieren oder andere Aufgaben ausführen können, die im Hauptthread ausgeführt werden müssen.

Wissen testen

In welchem Thread wird ein Web Worker ausgeführt?

Der Hauptthread.
Versuche es noch einmal.
Sein eigener Thread (auch als Web-Worker-Thread bezeichnet).
Richtig!
Der GPU-Thread.
Versuche es noch einmal.

Worauf können Web Worker zugreifen?

JavaScript-Primitive wie Arrays und Objekte.
Richtig!
Eine strikte Teilmenge der im window-Kontext verfügbaren APIs, einschließlich fetch.
Richtig!
Den window-Kontext, aber nur indirekt.
Richtig!

Wie kann ein Web Worker auf den Kontext „window“ zugreifen?

Direkt durch Verweisen auf Mitglieder des window-Objekts.
Versuche es noch einmal.
Ein Web Worker kann unter keinen Umständen auf das window zugreifen.
Versuche es noch einmal.
Über eine Messaging-Pipeline, die durch die Methode postMessage im Web-Worker-Kontext (self) ermöglicht wird.
Richtig!

Nächster Schritt: ein konkreter Web-Worker-Anwendungsfall

Im nächsten Modul wird ein konkreter Web-Worker-Anwendungsfall detailliert und demonstriert. In diesem Modul wird ein Web Worker verwendet, um eine JPEG-Datei von einer bestimmten URL abzurufen und ihre Exif-Metadaten in einem Web Worker zu lesen. Diese Daten werden dann an den Hauptthread zurückgesendet, damit sie dem Nutzer angezeigt werden.