Converting between iterables and web streams
It’s now easy to turn an iterator into a readable stream and a readable stream into an array. Let’s take a look.
ReadableStream.from()
ReadableStream.from
is currently supported in Firefox Nightly and Deno.
ReadableStream.from()
takes any sync or async iterable and returns a readable stream. The text of the PR to the spec reads:
This static method takes an async iterable and returns a ReadableStream pulling chunks from that async iterable. Sync iterables (including arrays and generators) are also supported, since GetIterator() already has all the necessary handling to adapt a sync iterator into an async iterator.
const syncIterable = ['hello', 'world'];
const stream1 = ReadableStream.from(syncIterable);
async function* createAsyncIterable() {
yield 'foo';
yield 'bar';
yield 'baz';
}
const stream2 = ReadableStream.from(createAsyncIterable());
Array.fromAsync()
Array.fromAsync
is currently supported in Safari 16.4, Firefox 115 and Bun. Caveat: Chrome and Safari do not treat streams as async iterables yet, so Array.fromAsync()
won’t work on streams in those browsers.
We already had Array.from
. Array.fromAsync
is the same but works with both synchronous and asynchronous iterables. fromAsync()
returns a promise that resolves with an array.
Readable streams are asynchronously iterable, so we can use fromAsync()
to turn a readable stream into an array. Each chunk of the stream becomes an array item.
It’s not a practical real-world example, but to keep things simple lets revisit the stream we created earlier:
async function* createAsyncIterable() {
yield 'foo';
yield 'bar';
yield 'baz';
}
const stream = ReadableStream.from(createAsyncIterable());
const array = await Array.fromAsync(stream);
console.log(array); // [ "foo", "bar", "baz" ]