1

Array.fromAsync()

 1 year ago
source link: https://2ality.com/2022/11/array-from-async.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

This blog post is about the ECMAScript proposal “Array.fromAsync for JavaScript” by J. S. Choi. It introduces a static method for converting asynchronous iterables to Arrays.

Tools for working with synchronous iterables  #

Currently JavaScript provides several tools for working with synchronous iterables – for example:

function* createSyncIterable() {
  yield 'a';
  yield 'b';
  yield 'c';
}

// Array-destructuring
const [elem0, elem1] = createSyncIterable();
assert.equal(elem0, 'a');
assert.equal(elem1, 'b');

// Spreading into Arrays
assert.deepEqual(
  ['>', ...createSyncIterable(), '<'],
  ['>', 'a', 'b', 'c', '<']
);

// Spreading into function arguments
const arr = [];
arr.push('>', ...createSyncIterable(), '<');
assert.deepEqual(
  arr,
  ['>', 'a', 'b', 'c', '<']
);

// Array.from()
assert.deepEqual(
  Array.from(createSyncIterable()),
  ['a', 'b', 'c']
);
assert.deepEqual(
  Array.from(createSyncIterable(), s => s + s),
  ['aa', 'bb', 'cc']
);

// for-of loop
for (const x of createSyncIterable()) {
  console.log(x);
}
// Output:
// a
// b
// c

For working with asynchronous iterables, we currently only have the for-await-of loop.

Array.fromAsync()  #

Array.fromAsync() is the asynchronous version of Array.from():

interface ArrayConstructor {
  fromAsync<T>(
    asyncIterable: AsyncIterable<T>
  ): Promise<Array<T>>;
  fromAsync<T, U>(
    asyncIterable: AsyncIterable<T>,
    mapFn: (value: T, index: number) => U,
    thisArg?: any
  ): Promise<Array<U>>;
  // ···
}

Array.fromAsync() accepts up to three arguments:

  • asyncIterable is the asynchronous iterable that is converted to an Array.
  • The optional mapFn lets us transform the iterated values before they are added to the Array that is returned. If we provide this argument, Array.fromAsync() works similarly to the Array method .map().
  • The optional thisArg lets us specify the value of this for mapFn.

Given that the values in asyncIterable can’t be collected synchronously, Array.fromAsync() works asynchronously and returns a Promise for an Array. Therefore, we await its results in the following example:

async function* createAsyncIterable() {
  yield 1;
  yield 2;
  yield 3;
}

assert.deepEqual(
  await Array.fromAsync(createAsyncIterable()),
  [1, 2, 3]
);
assert.deepEqual(
  await Array.fromAsync(createAsyncIterable(), x => x * x),
  [1, 4, 9]
);

An implementation of Array.fromAsync()  #

We could implement Array.fromAsync() like this:

async function arrayFromAsync(
  asyncIterable, mapFn=x=>x, thisArg=undefined
) {
  const result = [];
  for await (const elem of asyncIterable) {
    result.push(mapFn.call(thisArg, elem));
  }
  return result;
}

Example: reading chunks from a readable web stream  #

In Node.js, readable web streams are asynchronously iterable. Therefore, we can use Array.fromAsync() to collect all the chunks (pieces of data) of a ReadableStream in an Array.

We’ll read the following file data.txt:

First line
Second line

This is the code:

import {Readable} from 'node:stream';
import * as fs from 'node:fs';
const readableStream = Readable.toWeb(
  fs.createReadStream('data.txt', 'utf-8')
);
const chunks = await Array.fromAsync(readableStream);
assert.deepEqual(
  chunks,
  ['First line\nSecond line']
);

Further reading  #


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK