From 0c18c49f0efd8296e7cf73680c8df0674ac4131c Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 12 Dec 2019 14:40:50 +0100 Subject: [PATCH] stream: do not chunk strings and Buffer in Readable.from MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/30912 Reviewed-By: Ruben Bridgewater Reviewed-By: Michaƫl Zasso Reviewed-By: Anna Henningsen Reviewed-By: Rich Trott --- doc/api/stream.md | 4 ++++ lib/internal/streams/from.js | 12 ++++++++++++ test/parallel/test-readable-from.js | 13 ++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/api/stream.md b/doc/api/stream.md index a880bae5bbe31d..ad13e8ee6ade38 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1642,6 +1642,10 @@ readable.on('data', (chunk) => { }); ``` +Calling `Readable.from(string)` or `Readable.from(buffer)` will not have +the strings or buffers be iterated to match the other streams semantics +for performance reasons. + ## API for Stream Implementers diff --git a/lib/internal/streams/from.js b/lib/internal/streams/from.js index a060638df2dcfe..474db60b8930a2 100644 --- a/lib/internal/streams/from.js +++ b/lib/internal/streams/from.js @@ -4,6 +4,7 @@ const { Symbol, SymbolIterator } = primordials; +const { Buffer } = require('buffer'); const { ERR_INVALID_ARG_TYPE @@ -11,6 +12,17 @@ const { function from(Readable, iterable, opts) { let iterator; + if (typeof iterable === 'string' || iterable instanceof Buffer) { + return new Readable({ + objectMode: true, + ...opts, + read() { + this.push(iterable); + this.push(null); + } + }); + } + if (iterable && iterable[Symbol.asyncIterator]) iterator = iterable[Symbol.asyncIterator](); else if (iterable && iterable[SymbolIterator]) diff --git a/test/parallel/test-readable-from.js b/test/parallel/test-readable-from.js index e43cec6b1e5246..6cc9216a306378 100644 --- a/test/parallel/test-readable-from.js +++ b/test/parallel/test-readable-from.js @@ -56,13 +56,23 @@ async function toReadablePromises() { async function toReadableString() { const stream = Readable.from('abc'); - const expected = ['a', 'b', 'c']; + const expected = ['abc']; for await (const chunk of stream) { strictEqual(chunk, expected.shift()); } } +async function toReadableBuffer() { + const stream = Readable.from(Buffer.from('abc')); + + const expected = ['abc']; + + for await (const chunk of stream) { + strictEqual(chunk.toString(), expected.shift()); + } +} + async function toReadableOnData() { async function* generate() { yield 'a'; @@ -154,6 +164,7 @@ Promise.all([ toReadableSyncIterator(), toReadablePromises(), toReadableString(), + toReadableBuffer(), toReadableOnData(), toReadableOnDataNonObject(), destroysTheStreamWhenThrowing(),