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.

Die statische Methode Array.fromAsync() erstellt eine neue, flach kopierte Array-Instanz aus einem asynchronen Iterable, einem Iterable oder einem array-ähnlichen Objekt.

Syntax

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

Parameter

arrayLike

Ein asynchrones Iterable, ein Iterable oder ein array-ähnliches Objekt, das in ein Array konvertiert werden soll.

mapFn Optional

Eine Funktion, die auf jedes Element des Arrays angewendet wird. Wenn vorhanden, wird jeder Wert, der dem Array hinzugefügt werden soll, zuerst durch diese Funktion geleitet, und der Rückgabewert von mapFn wird stattdessen dem Array hinzugefügt (nachdem er awaited wurde). Die Funktion wird mit den folgenden Argumenten aufgerufen:

element

Das aktuelle Element, das im Array verarbeitet wird. Da alle Elemente zuerst awaited werden, wird dieser Wert niemals ein thenable sein.

index

Der Index des aktuellen Elements, das im Array verarbeitet wird.

thisArg Optional

Wert, der als this beim Ausführen von mapFn verwendet wird.

Rückgabewert

Ein neues Promise, dessen Erfüllungswert eine neue Array-Instanz ist.

Beschreibung

Array.fromAsync() ermöglicht es Ihnen, Arrays zu erstellen aus:

Array.fromAsync() durchläuft das asynchrone Iterable sehr ähnlich wie for await...of. Array.fromAsync() ist im Verhalten fast gleichwertig mit Array.from(), außer den folgenden Punkten:

  • Array.fromAsync() behandelt asynchrone iterierbare Objekte.
  • Array.fromAsync() gibt ein Promise zurück, das auf die Array-Instanz erfüllt.
  • Wenn Array.fromAsync() mit einem nicht asynchronen iterierbaren Objekt aufgerufen wird, wird jedes Element, das dem Array hinzugefügt werden soll, zuerst awaited.
  • Wenn ein mapFn bereitgestellt wird, werden dessen Eingaben und Ausgaben intern awaited.

Array.fromAsync() und Promise.all() können beide ein Iterable von Promises in ein Promise eines Arrays umwandeln. Es gibt jedoch zwei wesentliche Unterschiede:

  • Array.fromAsync() wartet auf jeden Wert, der aus dem Objekt nacheinander erzeugt wird. Promise.all() wartet auf alle Werte gleichzeitig.
  • Array.fromAsync() durchläuft das Iterable lazy und ruft den nächsten Wert erst ab, wenn der aktuelle abgeschlossen ist. Promise.all() ruft alle Werte im Voraus ab und wartet auf alle.

Beispiele

Array aus einem asynchronen 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 aus einem synchronen Iterable

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

Array aus einem synchronen Iterable, das Promises liefert

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

Array aus einem array-ähnlichen Objekt von 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]

Verwendung von mapFn

Sowohl die Eingabe als auch die Ausgabe von mapFn werden intern von Array.fromAsync() awaited.

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]

Vergleich mit Promise.all()

Array.fromAsync() wartet auf jeden Wert, der aus dem Objekt nacheinander erzeugt wird. Promise.all() wartet auf alle Werte gleichzeitig.

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

Keine Fehlerbehandlung für synchrone Iterables

Ähnlich wie bei for await...of, wenn das Objekt, das durchlaufen wird, ein synchrones Iterable ist und ein Fehler beim Iterieren auftritt, die return()-Methode des zugrunde liegenden Iterators nicht aufgerufen wird, sodass der Iterator nicht geschlossen wird.

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

Wenn Sie den Iterator schließen müssen, müssen Sie stattdessen eine for...of-Schleife verwenden und jeden Wert selbst awaiten.

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

Spezifikationen

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

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch