Start · Sprachen · JavaScript · Referenz · WorkerGlobalScope: unhandledrejection

WorkerGlobalScope: unhandledrejection

Ereignis

Wird im globalen Worker-Kontext ausgelöst, wenn ein Promise abgelehnt wird und bis zum Ende der aktuellen Mikrotask-Verarbeitung kein Ablehnungshandler angehängt ist.

seit JavaScript Baseline: alle modernen Browser (Chrome 49+, Firef Kategorie: webapi

Signatur

self.addEventListener("unhandledrejection", handler)

Beschreibung

Das Ereignis unhandledrejection wird an den globalen Geltungsbereich eines Workers (WorkerGlobalScope, also DedicatedWorkerGlobalScope, SharedWorkerGlobalScope oder ServiceWorkerGlobalScope) gesendet, wenn ein Promise abgelehnt wird und kein .catch()-Handler bzw. kein zweites Argument von .then() vorhanden ist. Das Ereignisobjekt ist ein PromiseRejectionEvent mit den Eigenschaften promise und reason.

Registrieren lässt sich der Handler entweder über self.addEventListener("unhandledrejection", handler) oder über die Eigenschaft self.onunhandledrejection = handler. Das ist das zentrale Werkzeug, um vergessene Fehlerbehandlungen in Workern zu protokollieren, etwa um sie an einen Logging-Dienst oder per postMessage() an den Haupt-Thread weiterzuleiten.

Ruft man event.preventDefault() auf, unterdrückt der Browser die Standardausgabe („Uncaught (in promise)“) in der Konsole. Das Ereignis ist abbrechbar (cancelable), wird aber nicht weitergereicht (bubbles ist false). Wird später doch noch ein Handler an das Promise angehängt, feuert zusätzlich das Ereignis rejectionhandled.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "unhandledrejection".
$handler Pflicht (event: PromiseRejectionEvent) => void Callback, der ein PromiseRejectionEvent erhält. Wichtige Eigenschaften: event.promise (das abgelehnte Promise) und event.reason (Ablehnungsgrund, oft ein Error).
$options boolean | AddEventListenerOptions false Optionale Listener-Optionen wie once oder signal.

Beispiele

Unbehandelte Ablehnungen im Worker protokollieren

// worker.js
self.addEventListener("unhandledrejection", (event) => {
  console.warn("Unbehandelte Ablehnung:", event.reason?.message ?? event.reason);
  // Standardausgabe in der Konsole unterdrücken
  event.preventDefault();
});

// Absichtlich ohne catch()
fetch("/gibt-es-nicht.json").then((res) => {
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
});
Unbehandelte Ablehnung: HTTP 404

Fehler an den Haupt-Thread weiterleiten (on-Property)

// worker.js
self.onunhandledrejection = (event) => {
  self.postMessage({
    type: "worker-error",
    message: String(event.reason?.message ?? event.reason),
    stack: event.reason?.stack ?? null
  });
};

const berechne = async (n) => {
  if (n < 0) throw new RangeError("n darf nicht negativ sein");
  return n * 2;
};

berechne(-1); // kein await, kein catch

// main.js
const worker = new Worker("worker.js");
worker.addEventListener("message", ({ data }) => {
  if (data.type === "worker-error") {
    console.error("Fehler im Worker:", data.message);
  }
});
Fehler im Worker: n darf nicht negativ sein

Listener wieder entfernen und rejectionhandled beobachten

// worker.js
const offen = new Set();

const onUnhandled = (event) => {
  offen.add(event.promise);
  console.log("Offen:", offen.size);
};

const onHandled = (event) => {
  offen.delete(event.promise);
  console.log("Nachträglich behandelt, offen:", offen.size);
};

self.addEventListener("unhandledrejection", onUnhandled);
self.addEventListener("rejectionhandled", onHandled);

const p = Promise.reject(new Error("später behandelt"));

setTimeout(() => {
  p.catch(() => {}); // löst rejectionhandled aus
  setTimeout(() => {
    self.removeEventListener("unhandledrejection", onUnhandled);
    self.removeEventListener("rejectionhandled", onHandled);
  }, 0);
}, 100);
Offen: 1 Nachträglich behandelt, offen: 0

// Wichtig · Fallstricke

  • Zeitpunkt: Das Ereignis feuert erst, nachdem die Mikrotask-Warteschlange abgearbeitet wurde. Ein .catch(), das synchron oder in derselben Mikrotask-Runde angehängt wird, verhindert es. Wird der Handler später angehängt, folgt rejectionhandled.
  • Kein Ersatz für Fehlerbehandlung: Das Ereignis dient der Diagnose. Einzelne Promises sollten weiterhin mit try/catch bzw. .catch() abgesichert werden.
  • Kein Weiterreichen an den Haupt-Thread: Ablehnungen im Worker lösen nicht das error-Ereignis des Worker-Objekts im Haupt-Thread aus. Wer sie dort sehen will, muss sie selbst per postMessage() übertragen. Dabei gilt: Error-Objekte lassen sich in modernen Browsern strukturiert klonen, sicherer ist aber die Übergabe von message und stack als Strings.
  • reason kann beliebig sein: Promise.reject(42) liefert eine Zahl, kein Error. Deshalb defensiv mit ?. zugreifen.
  • Kompatibilität: Firefox unterstützt das Ereignis erst ab Version 69. In Node.js heißt das Gegenstück process.on("unhandledRejection"). Das ist kein DOM-Ereignis und hat eine andere Signatur (reason, promise).
  • Das Unterdrücken per preventDefault() blendet Fehler in der Konsole aus. Das erschwert das Debuggen, wenn man sie nicht anderweitig protokolliert.