From be9f90eb01289d7f90aecfeb0ad12b894aff59ab Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Wed, 27 May 2026 00:16:34 -0700 Subject: [PATCH] stream: defer readable async iterator listener Defer installing the readable listener for async iteration until read() returns null. This avoids listener dispatch on the common path where data is already buffered while preserving end-of-stream error handling. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 --- lib/internal/streams/readable.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index 57aa71817e4fba..983a6f6e65ebe4 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -1380,6 +1380,7 @@ function streamToAsyncIterator(stream, options) { async function* createAsyncIterator(stream, options) { let callback = nop; + let isListening = false; function next(resolve) { if (this === stream) { @@ -1390,8 +1391,6 @@ async function* createAsyncIterator(stream, options) { } } - stream.on('readable', next); - let error; const cleanup = eos(stream, { writable: false }, (err) => { error = err ? aggregateTwoErrors(error, err) : null; @@ -1399,6 +1398,11 @@ async function* createAsyncIterator(stream, options) { callback = nop; }); + function setupReadable() { + isListening = true; + stream.on('readable', next); + } + try { while (true) { const chunk = stream.destroyed ? null : stream.read(); @@ -1409,6 +1413,9 @@ async function* createAsyncIterator(stream, options) { } else if (error === null) { return; } else { + if (!isListening) { + setupReadable(); + } await new Promise(next); } }