-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
stream: implement Readable.from async iterator utility
PR-URL: #27660 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
- Loading branch information
1 parent
333963e
commit ddb5152
Showing
4 changed files
with
314 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,4 +90,4 @@ Promise.all([ | |
catchesErrors(), | ||
stopListeningAfterCatchingError(), | ||
onceError() | ||
]); | ||
]).then(common.mustCall()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
'use strict'; | ||
|
||
const { mustCall } = require('../common'); | ||
const { once } = require('events'); | ||
const { Readable } = require('stream'); | ||
const { strictEqual } = require('assert'); | ||
|
||
async function toReadableBasicSupport() { | ||
async function * generate() { | ||
yield 'a'; | ||
yield 'b'; | ||
yield 'c'; | ||
} | ||
|
||
const stream = Readable.from(generate()); | ||
|
||
const expected = ['a', 'b', 'c']; | ||
|
||
for await (const chunk of stream) { | ||
strictEqual(chunk, expected.shift()); | ||
} | ||
} | ||
|
||
async function toReadableSyncIterator() { | ||
function * generate() { | ||
yield 'a'; | ||
yield 'b'; | ||
yield 'c'; | ||
} | ||
|
||
const stream = Readable.from(generate()); | ||
|
||
const expected = ['a', 'b', 'c']; | ||
|
||
for await (const chunk of stream) { | ||
strictEqual(chunk, expected.shift()); | ||
} | ||
} | ||
|
||
async function toReadablePromises() { | ||
const promises = [ | ||
Promise.resolve('a'), | ||
Promise.resolve('b'), | ||
Promise.resolve('c') | ||
]; | ||
|
||
const stream = Readable.from(promises); | ||
|
||
const expected = ['a', 'b', 'c']; | ||
|
||
for await (const chunk of stream) { | ||
strictEqual(chunk, expected.shift()); | ||
} | ||
} | ||
|
||
async function toReadableString() { | ||
const stream = Readable.from('abc'); | ||
|
||
const expected = ['a', 'b', 'c']; | ||
|
||
for await (const chunk of stream) { | ||
strictEqual(chunk, expected.shift()); | ||
} | ||
} | ||
|
||
async function toReadableOnData() { | ||
async function * generate() { | ||
yield 'a'; | ||
yield 'b'; | ||
yield 'c'; | ||
} | ||
|
||
const stream = Readable.from(generate()); | ||
|
||
let iterations = 0; | ||
const expected = ['a', 'b', 'c']; | ||
|
||
stream.on('data', (chunk) => { | ||
iterations++; | ||
strictEqual(chunk, expected.shift()); | ||
}); | ||
|
||
await once(stream, 'end'); | ||
|
||
strictEqual(iterations, 3); | ||
} | ||
|
||
async function toReadableOnDataNonObject() { | ||
async function * generate() { | ||
yield 'a'; | ||
yield 'b'; | ||
yield 'c'; | ||
} | ||
|
||
const stream = Readable.from(generate(), { objectMode: false }); | ||
|
||
let iterations = 0; | ||
const expected = ['a', 'b', 'c']; | ||
|
||
stream.on('data', (chunk) => { | ||
iterations++; | ||
strictEqual(chunk instanceof Buffer, true); | ||
strictEqual(chunk.toString(), expected.shift()); | ||
}); | ||
|
||
await once(stream, 'end'); | ||
|
||
strictEqual(iterations, 3); | ||
} | ||
|
||
async function destroysTheStreamWhenThrowing() { | ||
async function * generate() { | ||
throw new Error('kaboom'); | ||
} | ||
|
||
const stream = Readable.from(generate()); | ||
|
||
stream.read(); | ||
|
||
try { | ||
await once(stream, 'error'); | ||
} catch (err) { | ||
strictEqual(err.message, 'kaboom'); | ||
strictEqual(stream.destroyed, true); | ||
} | ||
} | ||
|
||
async function asTransformStream() { | ||
async function * generate(stream) { | ||
for await (const chunk of stream) { | ||
yield chunk.toUpperCase(); | ||
} | ||
} | ||
|
||
const source = new Readable({ | ||
objectMode: true, | ||
read() { | ||
this.push('a'); | ||
this.push('b'); | ||
this.push('c'); | ||
this.push(null); | ||
} | ||
}); | ||
|
||
const stream = Readable.from(generate(source)); | ||
|
||
const expected = ['A', 'B', 'C']; | ||
|
||
for await (const chunk of stream) { | ||
strictEqual(chunk, expected.shift()); | ||
} | ||
} | ||
|
||
Promise.all([ | ||
toReadableBasicSupport(), | ||
toReadableSyncIterator(), | ||
toReadablePromises(), | ||
toReadableString(), | ||
toReadableOnData(), | ||
toReadableOnDataNonObject(), | ||
destroysTheStreamWhenThrowing(), | ||
asTransformStream() | ||
]).then(mustCall()); |