From 5bec8224c3df0f8f66631f9f2803ecdcde90b4b9 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Sat, 2 Dec 2023 00:24:28 -0500 Subject: [PATCH] events: remove the abort listener on iterator completion The async iterator returned by the events.on API now cleans up the abort listener when the iterator ends regardless of success or failure. Fixes: https://github.com/nodejs/node/issues/51010 --- lib/events.js | 2 +- .../parallel/test-events-on-async-iterator.js | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/events.js b/lib/events.js index 3ba2484ece938f1..ef77af7ab3f4dc4 100644 --- a/lib/events.js +++ b/lib/events.js @@ -1169,7 +1169,7 @@ function on(emitter, event, options = kEmptyObject) { } if (signal) { kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; - eventTargetAgnosticAddListener( + addEventListener( signal, 'abort', abortListener, diff --git a/test/parallel/test-events-on-async-iterator.js b/test/parallel/test-events-on-async-iterator.js index 057af8537f3275d..fd31d1a33af6ab6 100644 --- a/test/parallel/test-events-on-async-iterator.js +++ b/test/parallel/test-events-on-async-iterator.js @@ -6,6 +6,7 @@ const assert = require('assert'); const { on, EventEmitter } = require('events'); const { NodeEventTarget, + kEvents } = require('internal/event_target'); async function basic() { @@ -372,6 +373,28 @@ async function abortableOnAfterDone() { }); } +async function abortListenerRemovedAfterComplete() { + const ee = new EventEmitter(); + const ac = new AbortController(); + + const i = setInterval(() => ee.emit('foo', 'foo'), 1); + try { + // Return case + const endedIterator = on(ee, 'foo', { signal: ac.signal }); + assert.ok(ac.signal[kEvents].size > 0); + endedIterator.return(); + assert.strictEqual(ac.signal[kEvents].size, 0); + + // Throw case + const throwIterator = on(ee, 'foo', { signal: ac.signal }); + assert.ok(ac.signal[kEvents].size > 0); + throwIterator.throw(new Error()); + assert.strictEqual(ac.signal[kEvents].size, 0); + } finally { + clearInterval(i); + } +} + async function run() { const funcs = [ basic, @@ -391,6 +414,7 @@ async function run() { eventTargetAbortableOnAfter, eventTargetAbortableOnAfter2, abortableOnAfterDone, + abortListenerRemovedAfterComplete, ]; for (const fn of funcs) {