stream: improve from perf
PR-URL: https://github.com/nodejs/node/pull/50359 Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
parent
4ddb263654
commit
10d51e82a6
@ -36,6 +36,7 @@ function from(Readable, iterable, opts) {
|
|||||||
throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable);
|
throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const readable = new Readable({
|
const readable = new Readable({
|
||||||
objectMode: true,
|
objectMode: true,
|
||||||
highWaterMark: 1,
|
highWaterMark: 1,
|
||||||
@ -46,11 +47,19 @@ function from(Readable, iterable, opts) {
|
|||||||
// Flag to protect against _read
|
// Flag to protect against _read
|
||||||
// being called before last iteration completion.
|
// being called before last iteration completion.
|
||||||
let reading = false;
|
let reading = false;
|
||||||
|
let isAsyncValues = false;
|
||||||
|
|
||||||
readable._read = function() {
|
readable._read = function() {
|
||||||
if (!reading) {
|
if (!reading) {
|
||||||
reading = true;
|
reading = true;
|
||||||
next();
|
|
||||||
|
if (isAsync) {
|
||||||
|
nextAsync();
|
||||||
|
} else if (isAsyncValues) {
|
||||||
|
nextSyncWithAsyncValues();
|
||||||
|
} else {
|
||||||
|
nextSyncWithSyncValues();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,29 +87,115 @@ function from(Readable, iterable, opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function next() {
|
// There are a lot of duplication here, it's done on purpose for performance
|
||||||
|
// reasons - avoid await when not needed.
|
||||||
|
|
||||||
|
function nextSyncWithSyncValues() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
const { value, done } = isAsync ?
|
const { value, done } = iterator.next();
|
||||||
await iterator.next() :
|
|
||||||
iterator.next();
|
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
readable.push(null);
|
readable.push(null);
|
||||||
} else {
|
return;
|
||||||
const res = (value &&
|
|
||||||
typeof value.then === 'function') ?
|
|
||||||
await value :
|
|
||||||
value;
|
|
||||||
if (res === null) {
|
|
||||||
reading = false;
|
|
||||||
throw new ERR_STREAM_NULL_VALUES();
|
|
||||||
} else if (readable.push(res)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
reading = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value &&
|
||||||
|
typeof value.then === 'function') {
|
||||||
|
return changeToAsyncValues(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
reading = false;
|
||||||
|
throw new ERR_STREAM_NULL_VALUES();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readable.push(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reading = false;
|
||||||
|
} catch (err) {
|
||||||
|
readable.destroy(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeToAsyncValues(value) {
|
||||||
|
isAsyncValues = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await value;
|
||||||
|
|
||||||
|
if (res === null) {
|
||||||
|
reading = false;
|
||||||
|
throw new ERR_STREAM_NULL_VALUES();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readable.push(res)) {
|
||||||
|
nextSyncWithAsyncValues();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reading = false;
|
||||||
|
} catch (err) {
|
||||||
|
readable.destroy(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function nextSyncWithAsyncValues() {
|
||||||
|
for (;;) {
|
||||||
|
try {
|
||||||
|
const { value, done } = iterator.next();
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
readable.push(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = (value &&
|
||||||
|
typeof value.then === 'function') ?
|
||||||
|
await value :
|
||||||
|
value;
|
||||||
|
|
||||||
|
if (res === null) {
|
||||||
|
reading = false;
|
||||||
|
throw new ERR_STREAM_NULL_VALUES();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readable.push(res)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reading = false;
|
||||||
|
} catch (err) {
|
||||||
|
readable.destroy(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function nextAsync() {
|
||||||
|
for (;;) {
|
||||||
|
try {
|
||||||
|
const { value, done } = await iterator.next();
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
readable.push(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
reading = false;
|
||||||
|
throw new ERR_STREAM_NULL_VALUES();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readable.push(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reading = false;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
readable.destroy(err);
|
readable.destroy(err);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user