diff --git a/lib/events.js b/lib/events.js index 1e568e1cf40b3e..50708f700584b1 100644 --- a/lib/events.js +++ b/lib/events.js @@ -965,6 +965,8 @@ async function once(emitter, name, options = kEmptyObject) { }; eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== 'error' && typeof emitter.once === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we listen to `error` events only on EventEmitters. emitter.once('error', errorListener); } function abortListener() { @@ -1004,9 +1006,7 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === 'function') { - // EventTarget does not have `error` event semantics like Node - // EventEmitters, we do not listen to `error` events here. - emitter.addEventListener(name, (arg) => { listener(arg); }, flags); + emitter.addEventListener(name, listener, flags); } else { throw new ERR_INVALID_ARG_TYPE('emitter', 'EventEmitter', emitter); } diff --git a/test/parallel/test-events-once.js b/test/parallel/test-events-once.js index 56042b1ecee4f9..6acb795653590b 100644 --- a/test/parallel/test-events-once.js +++ b/test/parallel/test-events-once.js @@ -1,5 +1,5 @@ 'use strict'; -// Flags: --no-warnings +// Flags: --expose-internals --no-warnings const common = require('../common'); const { once, EventEmitter } = require('events'); @@ -9,6 +9,7 @@ const { fail, rejects, } = require('assert'); +const { kEvents } = require('internal/event_target'); async function onceAnEvent() { const ee = new EventEmitter(); @@ -65,6 +66,32 @@ async function catchesErrors() { strictEqual(ee.listenerCount('myevent'), 0); } +async function catchesErrorsWithAbortSignal() { + const ee = new EventEmitter(); + const ac = new AbortController(); + const signal = ac.signal; + + const expected = new Error('boom'); + let err; + process.nextTick(() => { + ee.emit('error', expected); + }); + + try { + const promise = once(ee, 'myevent', { signal }); + strictEqual(ee.listenerCount('error'), 1); + strictEqual(signal[kEvents].size, 1); + + await promise; + } catch (e) { + err = e; + } + strictEqual(err, expected); + strictEqual(ee.listenerCount('error'), 0); + strictEqual(ee.listenerCount('myevent'), 0); + strictEqual(signal[kEvents].size, 0); +} + async function stopListeningAfterCatchingError() { const ee = new EventEmitter(); @@ -165,7 +192,10 @@ async function abortSignalAfterEvent() { ee.emit('foo'); ac.abort(); }); - await once(ee, 'foo', { signal: ac.signal }); + const promise = once(ee, 'foo', { signal: ac.signal }); + strictEqual(ac.signal[kEvents].size, 1); + await promise; + strictEqual(ac.signal[kEvents].size, 0); } async function abortSignalRemoveListener() { @@ -221,6 +251,7 @@ Promise.all([ onceAnEventWithNullOptions(), onceAnEventWithTwoArgs(), catchesErrors(), + catchesErrorsWithAbortSignal(), stopListeningAfterCatchingError(), onceError(), onceWithEventTarget(),