From 58374c5237b3c49ee1795dbe3084e2f996d604e3 Mon Sep 17 00:00:00 2001 From: Khoo Hao Yit <40757009+KhooHaoYit@users.noreply.github.com> Date: Sun, 13 Mar 2022 19:03:15 +0800 Subject: [PATCH 1/3] stream: do cleanup when iterator is destroyed --- lib/internal/streams/readable.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index 3fcd373cb1c708..4b7613fd13d081 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -1122,7 +1122,7 @@ async function* createAsyncIterator(stream, options) { stream.on('readable', next); let error; - eos(stream, { writable: false }, (err) => { + const cleanup = eos(stream, { writable: false }, (err) => { error = err ? aggregateTwoErrors(error, err) : null; callback(); callback = nop; @@ -1150,6 +1150,9 @@ async function* createAsyncIterator(stream, options) { (error === undefined || stream._readableState.autoDestroy) ) { destroyImpl.destroyer(stream, null); + } else { + stream.off('readable', next); + cleanup(); } } } From 7639e53ead842621e58cf47788def174d58b6a0a Mon Sep 17 00:00:00 2001 From: Khoo Hao Yit <40757009+KhooHaoYit@users.noreply.github.com> Date: Sun, 13 Mar 2022 21:15:38 +0800 Subject: [PATCH 2/3] test: check for dangling listeners --- .../test-stream-readable-async-iterators.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/parallel/test-stream-readable-async-iterators.js b/test/parallel/test-stream-readable-async-iterators.js index 87184662139ae5..21dd604c3f6bcd 100644 --- a/test/parallel/test-stream-readable-async-iterators.js +++ b/test/parallel/test-stream-readable-async-iterators.js @@ -789,6 +789,19 @@ async function tests() { } ); } + + // Check for dangling listeners + (async function() { + const readable = createReadable(); + const opts = { destroyOnReturn: false }; + while (readable.readable) { + for await (const chunk of readable.iterator(opts)) { + break; + } + } + + assert.deepStrictEqual(readable.eventNames(), []); + })().then(common.mustCall()); } { From d90fa5898067417a64d19096c49c53622e4efe4c Mon Sep 17 00:00:00 2001 From: Khoo Hao Yit <40757009+KhooHaoYit@users.noreply.github.com> Date: Sun, 13 Mar 2022 21:24:14 +0800 Subject: [PATCH 3/3] test: enable no-unused-vars ESLint rule --- test/parallel/test-stream-readable-async-iterators.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/parallel/test-stream-readable-async-iterators.js b/test/parallel/test-stream-readable-async-iterators.js index 21dd604c3f6bcd..e8b69612014ca5 100644 --- a/test/parallel/test-stream-readable-async-iterators.js +++ b/test/parallel/test-stream-readable-async-iterators.js @@ -795,6 +795,7 @@ async function tests() { const readable = createReadable(); const opts = { destroyOnReturn: false }; while (readable.readable) { + // eslint-disable-next-line no-unused-vars for await (const chunk of readable.iterator(opts)) { break; }