Array.fromAsync()

Baseline 2024

Newly available

Since January 2024, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

Array.fromAsync() 静态方法从 异步可迭代iterablearray-like 对象创建新的浅复制 Array 实例。

¥The Array.fromAsync() static method creates a new, shallow-copied Array instance from an async iterable, iterable, or array-like object.

语法

¥Syntax

js
Array.fromAsync(arrayLike)
Array.fromAsync(arrayLike, mapFn)
Array.fromAsync(arrayLike, mapFn, thisArg)

参数

¥Parameters

arrayLike

要转换为数组的异步可迭代、可迭代或类数组对象。

mapFn Optional

调用数组的每个元素的函数。如果提供,则首先将要添加到数组的每个值都通过此函数传递,然后将 mapFn 的返回值添加到数组(在成为 awaited 之后)。使用以下参数调用该函数:

element

数组中当前正在处理的元素。因为所有元素首先都是 awaited,所以该值永远不会是 thenable

index

数组中当前正在处理的元素的索引。

thisArg Optional

执行 mapFn 时用作 this 的值。

返回值

¥Return value

一个新的 Promise,其履行值是一个新的 Array 实例。

¥A new Promise whose fulfillment value is a new Array instance.

描述

¥Description

Array.fromAsync() 允许你从以下位置创建数组:

¥Array.fromAsync() lets you create arrays from:

Array.fromAsync() 以与 for await...of 非常相似的方式迭代异步可迭代。Array.fromAsync() 在行为方面几乎等同于 Array.from(),但以下内容除外:

¥Array.fromAsync() iterates the async iterable in a fashion very similar to for await...of. Array.fromAsync() is almost equivalent to Array.from() in terms of behavior, except the following:

  • Array.fromAsync() 处理异步可迭代对象。
  • Array.fromAsync() 返回满足数组实例的 Promise
  • 如果使用非异步可迭代对象调用 Array.fromAsync(),则要添加到数组的每个元素首先是 awaited
  • 如果提供了 mapFn,则内部等待其输入和输出。

Array.fromAsync()Promise.all() 都可以将可迭代的 Promise 转换为数组的 Promise。但是,有两个关键区别:

¥Array.fromAsync() and Promise.all() can both turn an iterable of promises into a promise of an array. However, there are two key differences:

  • Array.fromAsync() 等待从对象中顺序产生的每个值。Promise.all() 同时等待所有值。
  • Array.fromAsync() 延迟迭代可迭代对象,并且在当前值解决之前不会检索下一个值。Promise.all() 提前检索所有值并等待它们全部。

示例

¥Examples

来自异步可迭代的数组

¥Array from an async iterable

js
const asyncIterable = (async function* () {
  for (let i = 0; i < 5; i++) {
    await new Promise((resolve) => setTimeout(resolve, 10 * i));
    yield i;
  }
})();

Array.fromAsync(asyncIterable).then((array) => console.log(array));
// [0, 1, 2, 3, 4]

来自同步迭代的数组

¥Array from a sync iterable

js
Array.fromAsync(
  new Map([
    [1, 2],
    [3, 4],
  ]),
).then((array) => console.log(array));
// [[1, 2], [3, 4]]

来自同步迭代的数组,产生承诺

¥Array from a sync iterable that yields promises

js
Array.fromAsync(
  new Set([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]),
).then((array) => console.log(array));
// [1, 2, 3]

来自 Promise 的类数组对象的数组

¥Array from an array-like object of promises

js
Array.fromAsync({
  length: 3,
  0: Promise.resolve(1),
  1: Promise.resolve(2),
  2: Promise.resolve(3),
}).then((array) => console.log(array));
// [1, 2, 3]

使用 mapFn

¥Using mapFn

mapFn 的输入和输出都由 Array.fromAsync() 内部等待。

¥Both the input and output of mapFn are awaited internally by Array.fromAsync().

js
function delayedValue(v) {
  return new Promise((resolve) => setTimeout(() => resolve(v), 100));
}

Array.fromAsync(
  [delayedValue(1), delayedValue(2), delayedValue(3)],
  (element) => delayedValue(element * 2),
).then((array) => console.log(array));
// [2, 4, 6]

与 Promise.all() 的比较

¥Comparison with Promise.all()

Array.fromAsync() 等待从对象中顺序产生的每个值。Promise.all() 同时等待所有值。

¥Array.fromAsync() awaits each value yielded from the object sequentially. Promise.all() awaits all values concurrently.

js
function* makeIterableOfPromises() {
  for (let i = 0; i < 5; i++) {
    yield new Promise((resolve) => setTimeout(resolve, 100));
  }
}

(async () => {
  console.time("Array.fromAsync() time");
  await Array.fromAsync(makeIterableOfPromises());
  console.timeEnd("Array.fromAsync() time");
  // Array.fromAsync() time: 503.610ms

  console.time("Promise.all() time");
  await Promise.all(makeIterableOfPromises());
  console.timeEnd("Promise.all() time");
  // Promise.all() time: 101.728ms
})();

同步迭代没有错误处理

¥No error handling for sync iterables

for await...of 类似,如果正在迭代的对象是同步迭代器,并且迭代时抛出错误,则不会调用底层迭代器的 return() 方法,因此迭代器不会关闭。

¥Similar to for await...of, if the object being iterated is a sync iterable, and an error is thrown while iterating, the return() method of the underlying iterator will not be called, so the iterator is not closed.

js
function* generatorWithRejectedPromises() {
  try {
    yield 0;
    yield Promise.reject(3);
  } finally {
    console.log("called finally");
  }
}

(async () => {
  try {
    await Array.fromAsync(generatorWithRejectedPromises());
  } catch (e) {
    console.log("caught", e);
  }
})();
// caught 3
// No "called finally" message

如果需要关闭迭代器,则需要使用 for...of 循环,并自己使用 await 每个值。

¥If you need to close the iterator, you need to use a for...of loop instead, and await each value yourself.

js
(async () => {
  const arr = [];
  try {
    for (const val of generatorWithRejectedPromises()) {
      arr.push(await val);
    }
  } catch (e) {
    console.log("caught", e);
  }
})();
// called finally
// caught 3

规范

Specification
ES Array.fromAsync (2022)
# sec-array.fromAsync

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看