diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 49981b47e04aa8..17f433f03d939d 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -284,7 +284,8 @@ function readableAddChunk(stream, chunk, encoding, addToFront) { } function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync) { + if (state.flowing && state.length === 0 && !state.sync && + stream.listenerCount('data') > 0) { // Use the guard to avoid creating `Set()` repeatedly // when we have multiple pipes. if (state.multiAwaitDrain) { diff --git a/test/parallel/test-stream-readable-add-chunk-during-data.js b/test/parallel/test-stream-readable-add-chunk-during-data.js new file mode 100644 index 00000000000000..6c36359790633e --- /dev/null +++ b/test/parallel/test-stream-readable-add-chunk-during-data.js @@ -0,0 +1,21 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { Readable } = require('stream'); + +// Verify that .push() and .unshift() can be called from 'data' listeners. + +for (const method of ['push', 'unshift']) { + const r = new Readable({ read() {} }); + r.once('data', common.mustCall((chunk) => { + assert.strictEqual(r.readableLength, 0); + r[method](chunk); + assert.strictEqual(r.readableLength, chunk.length); + + r.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk.toString(), 'Hello, world'); + })); + })); + + r.push('Hello, world'); +}