Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 4 additions & 35 deletions lib/_stream_readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const {
// Lazy loaded to improve the startup performance.
let StringDecoder;
let createReadableStreamAsyncIterator;
let from;

Object.setPrototypeOf(Readable.prototype, Stream.prototype);
Object.setPrototypeOf(Readable, Stream);
Expand Down Expand Up @@ -1209,40 +1210,8 @@ function endReadableNT(state, stream) {
}

Readable.from = function(iterable, opts) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we just do Readable.from = require('internal/streams/from') now that we have core snapshots?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to backport this to 10, I don't think we have those there yet.
We can remove this type of "postponed loading" everywhere I think - would you mind to open an issue? We'd need to verify it does not slow thing down.

let iterator;
if (iterable && iterable[Symbol.asyncIterator])
iterator = iterable[Symbol.asyncIterator]();
else if (iterable && iterable[Symbol.iterator])
iterator = iterable[Symbol.iterator]();
else
throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable);

const readable = new Readable({
objectMode: true,
...opts
});
// Reading boolean to protect against _read
// being called before last iteration completion.
let reading = false;
readable._read = function() {
if (!reading) {
reading = true;
next();
}
};
async function next() {
try {
const { value, done } = await iterator.next();
if (done) {
readable.push(null);
} else if (readable.push(await value)) {
next();
} else {
reading = false;
}
} catch (err) {
readable.destroy(err);
}
if (from === undefined) {
from = require('internal/streams/from');
}
return readable;
return from(Readable, iterable, opts);
};
46 changes: 46 additions & 0 deletions lib/internal/streams/from.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

const {
ERR_INVALID_ARG_TYPE
} = require('internal/errors').codes;

function from(Readable, iterable, opts) {
let iterator;
if (iterable && iterable[Symbol.asyncIterator])
iterator = iterable[Symbol.asyncIterator]();
else if (iterable && iterable[Symbol.iterator])
iterator = iterable[Symbol.iterator]();
else
throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable);

const readable = new Readable({
objectMode: true,
...opts
});
// Reading boolean to protect against _read
// being called before last iteration completion.
let reading = false;
readable._read = function() {
if (!reading) {
reading = true;
next();
}
};
async function next() {
try {
const { value, done } = await iterator.next();
if (done) {
readable.push(null);
} else if (readable.push(await value)) {
next();
} else {
reading = false;
}
} catch (err) {
readable.destroy(err);
}
}
return readable;
}

module.exports = from;
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
'lib/internal/streams/async_iterator.js',
'lib/internal/streams/buffer_list.js',
'lib/internal/streams/duplexpair.js',
'lib/internal/streams/from.js',
'lib/internal/streams/legacy.js',
'lib/internal/streams/destroy.js',
'lib/internal/streams/state.js',
Expand Down