Signatur
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}`);
});
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);
}
});
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);
// 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, folgtrejectionhandled. - Kein Ersatz für Fehlerbehandlung: Das Ereignis dient der Diagnose. Einzelne Promises sollten weiterhin mit
try/catchbzw..catch()abgesichert werden. - Kein Weiterreichen an den Haupt-Thread: Ablehnungen im Worker lösen nicht das
error-Ereignis desWorker-Objekts im Haupt-Thread aus. Wer sie dort sehen will, muss sie selbst perpostMessage()übertragen. Dabei gilt:Error-Objekte lassen sich in modernen Browsern strukturiert klonen, sicherer ist aber die Übergabe vonmessageundstackals Strings. reasonkann beliebig sein:Promise.reject(42)liefert eine Zahl, keinError. 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.