Start · Sprachen · JavaScript · Referenz · Worker: message

Worker: message

Ereignis

Wird auf einem <code>Worker</code>-Objekt ausgelöst, wenn der Haupt-Thread eine Nachricht erhält, die der Worker per <code>postMessage()</code> gesendet hat.

seit JavaScript Baseline: alle Browser Kategorie: webapi

Signatur

worker.addEventListener("message", handler)

Beschreibung

Das message-Ereignis tritt am Worker-Objekt im übergeordneten Kontext auf, also meist im Haupt-Thread. Es feuert, sobald der Worker mit self.postMessage() bzw. postMessage() eine Nachricht verschickt. Das Ereignisobjekt ist ein MessageEvent. In dessen Eigenschaft data liegen die gesendeten Daten.

Einen Handler kannst du auf zwei Arten registrieren: mit worker.addEventListener("message", handler) oder über die Eigenschaft worker.onmessage = handler. Mit addEventListener sind mehrere Listener möglich und du kannst sie gezielt mit removeEventListener entfernen. Die on-Eigenschaft nimmt dagegen nur einen einzigen Handler auf.

Die Daten werden mit dem Structured-Clone-Algorithmus kopiert. Übertragen lassen sich deshalb Objekte, Arrays, Map, Set, Date, ArrayBuffer, Blob und Ähnliches, aber keine Funktionen und keine DOM-Knoten. Große Binärdaten kannst du als Transferable (z. B. ArrayBuffer) ohne Kopie übergeben.

Typische Einsatzfälle sind aufwendige Berechnungen (Parsen, Bildverarbeitung, Kryptografie). Der Worker meldet damit Ergebnisse oder Fortschritt zurück, ohne die Oberfläche zu blockieren.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignistyp, hier immer "message".
$handler Pflicht (event: MessageEvent) => void Callback, der das MessageEvent erhält. Wichtige Eigenschaften: data (gesendete Daten) und ports (übertragene MessagePorts).
$options boolean | AddEventListenerOptions false Optionen wie once oder signal (AbortSignal zum Entfernen des Listeners).

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Die Daten kommen über event.data im Handler an.

Beispiele

Ergebnis einer Berechnung empfangen (addEventListener)

// main.js
const worker = new Worker(new URL('./fib-worker.js', import.meta.url), { type: 'module' });

worker.addEventListener('message', (event) => {
  const { input, result } = event.data;
  console.log(`fib(${input}) = ${result}`);
});

worker.postMessage(30);

// fib-worker.js
const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2));
self.addEventListener('message', (event) => {
  const n = event.data;
  self.postMessage({ input: n, result: fib(n) });
});
fib(30) = 832040

Handler über die onmessage-Eigenschaft

const code = `self.onmessage = (e) => postMessage(e.data.toUpperCase());`;
const blobUrl = URL.createObjectURL(new Blob([code], { type: 'text/javascript' }));
const worker = new Worker(blobUrl);

worker.onmessage = (event) => {
  console.log('Antwort:', event.data);
  worker.terminate();
  URL.revokeObjectURL(blobUrl);
};

worker.postMessage('hallo worker');
Antwort: HALLO WORKER

Fortschrittsmeldungen und Listener wieder entfernen

const worker = new Worker('progress-worker.js');

const onProgress = (event) => {
  const { type, percent, result } = event.data;
  if (type === 'progress') {
    console.log(`Fortschritt: ${percent} %`);
  } else if (type === 'done') {
    console.log('Fertig:', result);
    worker.removeEventListener('message', onProgress);
    worker.terminate();
  }
};

worker.addEventListener('message', onProgress);
worker.postMessage({ items: 1000 });

// progress-worker.js
// self.onmessage = ({ data }) => {
//   for (let i = 1; i <= 4; i++) postMessage({ type: 'progress', percent: i * 25 });
//   postMessage({ type: 'done', result: data.items * 2 });
// };
Fortschritt: 25 % Fortschritt: 50 % Fortschritt: 75 % Fortschritt: 100 % Fertig: 2000

Worker-Antwort als Promise kapseln

const worker = new Worker('calc-worker.js');
let nextId = 0;

const request = (payload) => new Promise((resolve) => {
  const id = nextId++;
  const listener = ({ data }) => {
    if (data.id !== id) return;
    worker.removeEventListener('message', listener);
    resolve(data.result);
  };
  worker.addEventListener('message', listener);
  worker.postMessage({ id, payload });
});

const sum = await request([1, 2, 3, 4]);
console.log('Summe:', sum);

// calc-worker.js
// self.onmessage = ({ data }) =>
//   postMessage({ id: data.id, result: data.payload.reduce((a, b) => a + b, 0) });
Summe: 10

// Wichtig · Fallstricke

  • Nicht serialisierbare Daten: Nicht klonbare Werte wie Funktionen, DOM-Knoten oder manche Klasseninstanzen lösen nicht message aus. Stattdessen wirft schon postMessage() eine DataCloneError-Ausnahme. Kann eine eingegangene Nachricht auf der Empfängerseite nicht deserialisiert werden, feuert messageerror.
  • Prototypen gehen verloren: Klasseninstanzen kommen als einfache Objekte an, und Getter bzw. Methoden fehlen danach.
  • Fehler im Worker kommen nicht über message an. Für sie gibt es das error-Ereignis am Worker-Objekt.
  • Transferables: Einen übertragenen ArrayBuffer (postMessage(buf, [buf])) kann der Sender danach nicht mehr verwenden, seine byteLength ist dann 0.
  • Sicherheit: Behandle event.data als nicht vertrauenswürdig, wenn der Worker Fremddaten verarbeitet. Schreibe die Daten also nicht ungeprüft per innerHTML ins DOM (XSS-Gefahr). Worker-Skripte unterliegen der Same-Origin-Policy und der CSP-Direktive worker-src.
  • Kompatibilität: Wird von allen modernen Browsern unterstützt. Modul-Worker ({ type: 'module' }) funktionieren in Firefox erst ab Version 114. Node.js nutzt stattdessen worker_threads mit worker.on('message'), dort kommen die Daten direkt ohne event.data an.