Skip to content

Commit 1847f38

Browse files
author
Nitzan Uziely
committed
events: change EventTarget handler exception behavior
Change the behavior of EventTarget, instead of emitting 'error' on handler exception, emit 'uncaughtException'. Fixes: #36770
1 parent fe43bd8 commit 1847f38

File tree

3 files changed

+19
-14
lines changed

3 files changed

+19
-14
lines changed

doc/api/events.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,9 @@ setMaxListeners(5, target, emitter);
11371137
<!-- YAML
11381138
added: v14.5.0
11391139
changes:
1140+
- version: REPLACEME
1141+
pr-url: https://github.com/nodejs/node/pull/37237
1142+
description: changed EventTarget error handling.
11401143
- version: v15.4.0
11411144
pr-url: https://github.com/nodejs/node/pull/35949
11421145
description: No longer experimental.
@@ -1247,9 +1250,9 @@ target.addEventListener('foo', handler4, { once: true });
12471250
### `EventTarget` error handling
12481251

12491252
When a registered event listener throws (or returns a Promise that rejects),
1250-
by default the error is forwarded to the `process.on('error')` event
1251-
on `process.nextTick()`. Throwing within an event listener will *not* stop
1252-
the other registered handlers from being invoked.
1253+
by default the error is forwarded to the `process.on('uncaughtException')`
1254+
event on `process.nextTick()`. Throwing within an event listener will *not*
1255+
stop the other registered handlers from being invoked.
12531256

12541257
The `EventTarget` does not implement any special default handling for
12551258
`'error'` type events.

lib/internal/event_target.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,9 @@ class EventTarget {
420420
}
421421
const result = FunctionPrototypeCall(handler.callback, this, arg);
422422
if (result !== undefined && result !== null)
423-
addCatch(this, result, createEvent());
423+
addCatch(result);
424424
} catch (err) {
425-
emitUnhandledRejectionOrErr(this, err, createEvent());
425+
emitUncaughtException(err);
426426
}
427427

428428
handler = next;
@@ -582,19 +582,19 @@ function isEventTarget(obj) {
582582
return obj?.constructor?.[kIsEventTarget];
583583
}
584584

585-
function addCatch(that, promise, event) {
585+
function addCatch(promise) {
586586
const then = promise.then;
587587
if (typeof then === 'function') {
588588
FunctionPrototypeCall(then, promise, undefined, function(err) {
589589
// The callback is called with nextTick to avoid a follow-up
590590
// rejection from this promise.
591-
process.nextTick(emitUnhandledRejectionOrErr, that, err, event);
591+
emitUncaughtException(err);
592592
});
593593
}
594594
}
595595

596-
function emitUnhandledRejectionOrErr(that, err, event) {
597-
process.emit('error', err, event);
596+
function emitUncaughtException(err) {
597+
process.nextTick(() => { throw err; });
598598
}
599599

600600
function makeEventHandler(handler) {

test/parallel/test-eventtarget.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,16 @@ let asyncTest = Promise.resolve();
176176
}
177177

178178
{
179-
const uncaughtException = common.mustCall((err, event) => {
179+
const uncaughtException = common.mustCall((err, origin) => {
180180
strictEqual(err.message, 'boom');
181-
strictEqual(event.type, 'foo');
181+
strictEqual(origin, 'uncaughtException');
182182
}, 4);
183183

184-
// Whether or not the handler function is async or not, errors
185-
// are routed to uncaughtException
186-
process.on('error', uncaughtException);
184+
// Make sure that we no longer call 'error' on error.
185+
process.on('error', common.mustNotCall());
186+
// Don't call rejection even for async handlers.
187+
process.on('unhandledRejection', common.mustNotCall());
188+
process.on('uncaughtException', uncaughtException);
187189

188190
const eventTarget = new EventTarget();
189191

0 commit comments

Comments
 (0)