diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index d4096a30994f44..0e8f114c4168b4 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -631,6 +631,13 @@ function howMuchToRead(n, state) { if ((state[kState] & kObjectMode) !== 0) return 1; if (NumberIsNaN(n)) { + // Fast path for buffers. + if ((state[kState] & kDecoder) === 0) { + return state.length + ? state.buffer[state.bufferIndex].length + : state.length; + } + // Only flow one buffer at a time. if ((state[kState] & kFlowing) !== 0 && state.length) return state.buffer[state.bufferIndex].length; diff --git a/test/parallel/test-stream-compose.js b/test/parallel/test-stream-compose.js index d7a54e177668a2..f4da6a5cb86986 100644 --- a/test/parallel/test-stream-compose.js +++ b/test/parallel/test-stream-compose.js @@ -490,7 +490,7 @@ const assert = require('assert'); newStream.end(); - assert.deepStrictEqual(await newStream.toArray(), [Buffer.from('Steve RogersOn your left')]); + assert.deepStrictEqual(await newStream.toArray(), [Buffer.from('Steve Rogers'), Buffer.from('On your left')]); })().then(common.mustCall()); } diff --git a/test/parallel/test-stream-push-strings.js b/test/parallel/test-stream-push-strings.js index d582c8add005a5..5fece74a115cf3 100644 --- a/test/parallel/test-stream-push-strings.js +++ b/test/parallel/test-stream-push-strings.js @@ -59,7 +59,7 @@ ms.on('readable', function() { results.push(String(chunk)); }); -const expect = [ 'first chunksecond to last chunk', 'last chunk' ]; +const expect = [ 'first chunk', 'second to last chunk', 'last chunk' ]; process.on('exit', function() { assert.strictEqual(ms._chunks, -1); assert.deepStrictEqual(results, expect); diff --git a/test/parallel/test-stream-readable-emittedReadable.js b/test/parallel/test-stream-readable-emittedReadable.js index ba613f9e9ff19d..ffaf1d5b943334 100644 --- a/test/parallel/test-stream-readable-emittedReadable.js +++ b/test/parallel/test-stream-readable-emittedReadable.js @@ -10,7 +10,7 @@ const readable = new Readable({ // Initialized to false. assert.strictEqual(readable._readableState.emittedReadable, false); -const expected = [Buffer.from('foobar'), Buffer.from('quo'), null]; +const expected = [Buffer.from('foo'), Buffer.from('bar'), Buffer.from('quo'), null]; readable.on('readable', common.mustCall(() => { // emittedReadable should be true when the readable event is emitted assert.strictEqual(readable._readableState.emittedReadable, true); diff --git a/test/parallel/test-stream-readable-infinite-read.js b/test/parallel/test-stream-readable-infinite-read.js index df88d78b74c36f..c9323e54dd80c0 100644 --- a/test/parallel/test-stream-readable-infinite-read.js +++ b/test/parallel/test-stream-readable-infinite-read.js @@ -26,8 +26,8 @@ readable.on('readable', common.mustCall(function() { // TODO(mcollina): there is something odd in the highWaterMark logic // investigate. if (i === 1) { - assert.strictEqual(data.length, 8192 * 2); + assert.strictEqual(data.length, 8192); } else { - assert.strictEqual(data.length, 8192 * 3); + assert.strictEqual(data.length, 8192); } }, 11)); diff --git a/test/parallel/test-stream-readable-readable-one.js b/test/parallel/test-stream-readable-readable-one.js new file mode 100644 index 00000000000000..c15df5777cab6e --- /dev/null +++ b/test/parallel/test-stream-readable-readable-one.js @@ -0,0 +1,20 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +const { Readable } = require('stream'); + +// Read one buffer at a time and don't waste cycles allocating +// and copying into a new larger buffer. +{ + const r = new Readable({ + read() {} + }); + const buffers = [Buffer.allocUnsafe(5), Buffer.allocUnsafe(10)]; + for (const buf of buffers) { + r.push(buf); + } + for (const buf of buffers) { + assert.strictEqual(r.read(), buf); + } +} diff --git a/test/parallel/test-stream-typedarray.js b/test/parallel/test-stream-typedarray.js index ae5846da09dbbe..5ef2733a91bdbb 100644 --- a/test/parallel/test-stream-typedarray.js +++ b/test/parallel/test-stream-typedarray.js @@ -83,9 +83,19 @@ const views = common.getArrayBufferViews(buffer); readable.push(views[2]); readable.unshift(views[0]); - const buf = readable.read(); + let buf; + + buf = readable.read(); + assert(buf instanceof Buffer); + assert.deepStrictEqual([...buf], [...views[0]]); + + buf = readable.read(); + assert(buf instanceof Buffer); + assert.deepStrictEqual([...buf], [...views[1]]); + + buf = readable.read(); assert(buf instanceof Buffer); - assert.deepStrictEqual([...buf], [...views[0], ...views[1], ...views[2]]); + assert.deepStrictEqual([...buf], [...views[2]]); } { diff --git a/test/parallel/test-stream-uint8array.js b/test/parallel/test-stream-uint8array.js index f1de4c873fd3a8..a34f6e1e5a48d8 100644 --- a/test/parallel/test-stream-uint8array.js +++ b/test/parallel/test-stream-uint8array.js @@ -80,9 +80,15 @@ const GHI = new Uint8Array([0x47, 0x48, 0x49]); readable.push(DEF); readable.unshift(ABC); - const buf = readable.read(); + let buf; + + buf = readable.read(); + assert(buf instanceof Buffer); + assert.deepStrictEqual([...buf], [...ABC]); + + buf = readable.read(); assert(buf instanceof Buffer); - assert.deepStrictEqual([...buf], [...ABC, ...DEF]); + assert.deepStrictEqual([...buf], [...DEF]); } { diff --git a/test/parallel/test-stream2-transform.js b/test/parallel/test-stream2-transform.js index f222f1c03b48b5..457001fd886932 100644 --- a/test/parallel/test-stream2-transform.js +++ b/test/parallel/test-stream2-transform.js @@ -282,7 +282,9 @@ const { PassThrough, Transform } = require('stream'); pt.write(Buffer.from('ef'), common.mustCall(function() { pt.end(); })); - assert.strictEqual(pt.read().toString(), 'abcdef'); + assert.strictEqual(pt.read().toString(), 'abc'); + assert.strictEqual(pt.read().toString(), 'd'); + assert.strictEqual(pt.read().toString(), 'ef'); assert.strictEqual(pt.read(), null); }); });