Skip to content

Commit 43c3b43

Browse files
wwwzbwcomruyadorno
authored andcommitted
stream: make Readable.from performance better
PR-URL: #37609 Reviewed-By: Robert Nagy <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent f07428a commit 43c3b43

File tree

2 files changed

+58
-19
lines changed

2 files changed

+58
-19
lines changed

benchmark/streams/readable-from.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const Readable = require('stream').Readable;
5+
6+
const bench = common.createBenchmark(main, {
7+
n: [1e7],
8+
});
9+
10+
async function main({ n }) {
11+
const arr = [];
12+
for (let i = 0; i < n; i++) {
13+
arr.push(`${i}`);
14+
}
15+
16+
const s = new Readable.from(arr);
17+
18+
bench.start();
19+
s.on('data', (data) => {
20+
// eslint-disable-next-line no-unused-expressions
21+
data;
22+
});
23+
s.on('close', () => {
24+
bench.end(n);
25+
});
26+
}

lib/internal/streams/from.js

+32-19
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const {
44
PromisePrototypeThen,
55
SymbolAsyncIterator,
6-
SymbolIterator
6+
SymbolIterator,
77
} = primordials;
88
const { Buffer } = require('buffer');
99

@@ -25,18 +25,22 @@ function from(Readable, iterable, opts) {
2525
});
2626
}
2727

28-
if (iterable && iterable[SymbolAsyncIterator])
28+
let isAsync = false;
29+
if (iterable && iterable[SymbolAsyncIterator]) {
30+
isAsync = true;
2931
iterator = iterable[SymbolAsyncIterator]();
30-
else if (iterable && iterable[SymbolIterator])
32+
} else if (iterable && iterable[SymbolIterator]) {
33+
isAsync = false;
3134
iterator = iterable[SymbolIterator]();
32-
else
35+
} else {
3336
throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable);
37+
}
3438

3539
const readable = new Readable({
3640
objectMode: true,
3741
highWaterMark: 1,
3842
// TODO(ronag): What options should be allowed?
39-
...opts
43+
...opts,
4044
});
4145

4246
// Flag to protect against _read
@@ -75,23 +79,32 @@ function from(Readable, iterable, opts) {
7579
}
7680

7781
async function next() {
78-
try {
79-
const { value, done } = await iterator.next();
80-
if (done) {
81-
readable.push(null);
82-
} else {
83-
const res = await value;
84-
if (res === null) {
85-
reading = false;
86-
throw new ERR_STREAM_NULL_VALUES();
87-
} else if (readable.push(res)) {
88-
next();
82+
for (;;) {
83+
try {
84+
const { value, done } = isAsync ?
85+
await iterator.next() :
86+
iterator.next();
87+
88+
if (done) {
89+
readable.push(null);
8990
} else {
90-
reading = false;
91+
const res = (value &&
92+
typeof value.then === 'function') ?
93+
await value :
94+
value;
95+
if (res === null) {
96+
reading = false;
97+
throw new ERR_STREAM_NULL_VALUES();
98+
} else if (readable.push(res)) {
99+
continue;
100+
} else {
101+
reading = false;
102+
}
91103
}
104+
} catch (err) {
105+
readable.destroy(err);
92106
}
93-
} catch (err) {
94-
readable.destroy(err);
107+
break;
95108
}
96109
}
97110
return readable;

0 commit comments

Comments
 (0)