Spec-Zone.ru › JavaScript

Array.fromAsync()

Базовая поддержка Широко доступно

Эта функция хорошо зарекомендовала себя и работает на множестве устройств и версий браузеров. Она доступна в браузерах с января 2024 года.

Статический метод Array.fromAsync() создает новый, мелкокопированный экземпляр Array из асинхронного итерируемого объекта, итерируемого объекта или массивоподобного объекта.

Синтаксис

Array.fromAsync(items)
Array.fromAsync(items, mapFn)
Array.fromAsync(items, mapFn, thisArg)

Параметры

items
Асинхронный итерируемый, итерируемый или массивоподобный объект для преобразования в массив.
mapFn Необязательный
Функция, которая будет вызвана для каждого элемента массива. Если предоставлена, каждое значение, добавляемое в массив, сначала проходит через эту функцию, и возвращаемое значение mapFn добавляется в массив вместо него (после ожидания). Функция вызывается со следующими аргументами:
element
Текущий элемент, обрабатываемый в массиве. Если items является синхронным итерируемым или массивоподобным объектом, то все элементы сначала ожидаются, и element никогда не будет thenable. Если items является асинхронным итерируемым объектом, то каждое возвращаемое значение передается как есть.
index
Индекс текущего элемента, обрабатываемого в массиве.
thisArg Необязательный
Значение, которое будет использоваться как this при выполнении mapFn.

Возвращаемое значение

Новый Promise, значение которого при выполнении является новым экземпляром Array.

Описание

Array.fromAsync() позволяет создавать массивы из:

  • асинхронных итерируемых объектов (таких как ReadableStream и AsyncGenerator); или, если объект не является асинхронным итерируемым,
  • итерируемых объектов (таких как Map и Set); или, если объект не является итерируемым,
  • массивоподобных объектов (объектов с свойством length и индексированными элементами).

Array.fromAsync() итерирует асинхронный итерируемый объект способом, очень похожим на for await...of. Array.fromAsync(items) в целом эквивалентен следующему коду, если items является асинхронным или синхронным итерируемым объектом:

const result = [];
for await (const element of items) {
  result.push(element);
}

Array.fromAsync() почти эквивалентен Array.from() по поведению, за исключением следующего:

  • Array.fromAsync() обрабатывает асинхронные итерируемые объекты.
  • Array.fromAsync() возвращает Promise, который выполняется до экземпляра массива.
  • Если Array.fromAsync() вызывается с неасинхронным итерируемым объектом, каждый элемент, добавляемый в массив, сначала ожидается.
  • Если предоставлен mapFn, его выходные данные также внутренне ожидаются.

Array.fromAsync() и Promise.all() могут преобразовывать итерируемый объект промисов в промис массива. Однако есть два ключевых отличия:

  • Array.fromAsync() последовательно ожидает каждое значение, возвращаемое объектом. Promise.all() одновременно ожидает все значения.
  • Array.fromAsync() лениво итерирует итерируемый объект и не получает следующее значение, пока текущее не будет разрешено. Promise.all() получает все значения заранее и ожидает их всех.

Примеры

Массив из асинхронного итерируемого объекта

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]

Когда items является асинхронным итерируемым объектом, где value каждого результата также является промисом, то эти промисы добавляются в результирующий массив без ожидания. Это соответствует поведению for await...of.

function createAsyncIter() {
  let i = 0;
  return {
    [Symbol.asyncIterator]() {
      return {
        async next() {
          if (i > 2) return { done: true };
          i++;
          return { value: Promise.resolve(i), done: false };
        },
      };
    },
  };
}

Array.fromAsync(createAsyncIter()).then((array) => console.log(array));
// (3) [Promise, Promise, Promise]

Примечание: На практике вы редко столкнетесь с асинхронным итерируемым объектом, который возвращает промисы, потому что если вы реализуете его с помощью функции асинхронного генератора, то выражение yield автоматически распаковывает промисы.

Массив из синхронного итерируемого объекта

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

Массив из синхронного итерируемого объекта, возвращающего промисы

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

Массив из массивоподобного объекта промисов

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 с синхронным итерируемым объектом

Когда items является синхронным итерируемым или массивоподобным объектом, как входные, так и выходные данные mapFn внутренне ожидаются Array.fromAsync().

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]

Использование mapFn с асинхронным итерируемым объектом

Когда items является асинхронным итерируемым объектом, входные данные для mapFn не ожидаются, а выходные данные ожидаются. Используя ту же функцию createAsyncIter, что и выше:

Array.fromAsync(createAsyncIter(), async (element) => (await element) * 2).then(
  (array) => console.log(array),
);
// [2, 4, 6]

Любопытно, что это означает, что Array.fromAsync(createAsyncIter()) не эквивалентен Array.fromAsync(createAsyncIter(), (element) => element), потому что последний ожидает каждое возвращаемое значение, а первый — нет.

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

Сравнение с Promise.all()

Array.fromAsync() последовательно ожидает каждое значение, возвращаемое объектом. Promise.all() одновременно ожидает все значения.

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
})();

Закрытие синхронных итерируемых объектов при отклонении

Аналогично for await...of, если итерируемый объект является синхронным итерируемым, и возвращаемый промис отклоняется, метод return() базового итератора будет вызван, если он существует, чтобы позволить итератору выполнить очистку.

function* generatorWithRejectedPromises() {
  try {
    yield 0;
    yield Promise.reject(new Error("error"));
  } finally {
    console.log("called finally");
  }
}

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

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-array.fromasync

Совместимость с браузерами

Desktop Mobile Server
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
fromAsync
121
121
115
107
16.4
121
115
81
16.4
25.0
121
16.4
1.0.0
1.38
22.0.0

См. также

  • Polyfill для Array.fromAsync в core-js
  • Руководство по индексированным коллекциям
  • Array
  • Array()
  • Array.of()
  • Array.from()
  • for await...of

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API