Skip to content

Commit 0c5092c

Browse files
daeyeondanielleadams
authored andcommitted
events: fix adding abort listener in events.once
Event listeners passed to un/subscribe the abort event are mismatched. This removes the wrapper function in `eventTargetAgnosticAddListener()` and directly passes the given listener to the `EventTarget`. IMO, removing the wrapper seems harmless, and the `AbortSignal` is seemingly the only `EventTarget` passed to this function for now. Fixes: #43337 Refs: #33659 Refs: #34997 Signed-off-by: Daeyeon Jeong daeyeon.dev@gmail.com PR-URL: #43373 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 517f17b commit 0c5092c

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

lib/events.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,8 @@ async function once(emitter, name, options = kEmptyObject) {
972972
};
973973
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
974974
if (name !== 'error' && typeof emitter.once === 'function') {
975+
// EventTarget does not have `error` event semantics like Node
976+
// EventEmitters, we listen to `error` events only on EventEmitters.
975977
emitter.once('error', errorListener);
976978
}
977979
function abortListener() {
@@ -1011,9 +1013,7 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
10111013
emitter.on(name, listener);
10121014
}
10131015
} else if (typeof emitter.addEventListener === 'function') {
1014-
// EventTarget does not have `error` event semantics like Node
1015-
// EventEmitters, we do not listen to `error` events here.
1016-
emitter.addEventListener(name, (arg) => { listener(arg); }, flags);
1016+
emitter.addEventListener(name, listener, flags);
10171017
} else {
10181018
throw new ERR_INVALID_ARG_TYPE('emitter', 'EventEmitter', emitter);
10191019
}

test/parallel/test-events-once.js

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
2-
// Flags: --no-warnings
2+
// Flags: --expose-internals --no-warnings
33

44
const common = require('../common');
55
const { once, EventEmitter } = require('events');
@@ -9,6 +9,7 @@ const {
99
fail,
1010
rejects,
1111
} = require('assert');
12+
const { kEvents } = require('internal/event_target');
1213

1314
async function onceAnEvent() {
1415
const ee = new EventEmitter();
@@ -65,6 +66,32 @@ async function catchesErrors() {
6566
strictEqual(ee.listenerCount('myevent'), 0);
6667
}
6768

69+
async function catchesErrorsWithAbortSignal() {
70+
const ee = new EventEmitter();
71+
const ac = new AbortController();
72+
const signal = ac.signal;
73+
74+
const expected = new Error('boom');
75+
let err;
76+
process.nextTick(() => {
77+
ee.emit('error', expected);
78+
});
79+
80+
try {
81+
const promise = once(ee, 'myevent', { signal });
82+
strictEqual(ee.listenerCount('error'), 1);
83+
strictEqual(signal[kEvents].size, 1);
84+
85+
await promise;
86+
} catch (e) {
87+
err = e;
88+
}
89+
strictEqual(err, expected);
90+
strictEqual(ee.listenerCount('error'), 0);
91+
strictEqual(ee.listenerCount('myevent'), 0);
92+
strictEqual(signal[kEvents].size, 0);
93+
}
94+
6895
async function stopListeningAfterCatchingError() {
6996
const ee = new EventEmitter();
7097

@@ -165,7 +192,10 @@ async function abortSignalAfterEvent() {
165192
ee.emit('foo');
166193
ac.abort();
167194
});
168-
await once(ee, 'foo', { signal: ac.signal });
195+
const promise = once(ee, 'foo', { signal: ac.signal });
196+
strictEqual(ac.signal[kEvents].size, 1);
197+
await promise;
198+
strictEqual(ac.signal[kEvents].size, 0);
169199
}
170200

171201
async function abortSignalRemoveListener() {
@@ -221,6 +251,7 @@ Promise.all([
221251
onceAnEventWithNullOptions(),
222252
onceAnEventWithTwoArgs(),
223253
catchesErrors(),
254+
catchesErrorsWithAbortSignal(),
224255
stopListeningAfterCatchingError(),
225256
onceError(),
226257
onceWithEventTarget(),

0 commit comments

Comments
 (0)