Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

Array.fromAsync()

Baseline
Weitgehend verfügbar

Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit Januar 2024 browserübergreifend verfügbar.

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(items)
Array.fromAsync(items, mapFn)
Array.fromAsync(items, mapFn, thisArg)

Parameter

items

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

mapFn Optional

Eine Funktion, die auf jedes Element des Arrays angewendet wird. Wenn bereitgestellt, 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. Wenn items ein synchrones Iterable oder array-ähnliches Objekt ist, werden alle Elemente zuerst awaited, und element wird nie ein thenable sein. Wenn items ein asynchrones Iterable ist, wird jeder erzeugte Wert unverändert übergeben.

index

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

thisArg Optional

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

Rückgabewert

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

Beschreibung

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

Array.fromAsync() iteriert das asynchrone Iterable auf eine Art und Weise, die sehr ähnlich zu for await...of ist. Array.fromAsync(items) ist im Allgemeinen äquivalent zu folgendem Code, wenn items ein asynchrones Iterable oder synchrones Iterable ist:

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

Array.fromAsync() ist in Bezug auf das Verhalten fast gleichwertig mit Array.from(), außer den folgenden Unterschieden:

  • Array.fromAsync() verarbeitet asynchrone Iterable-Objekte.
  • Array.fromAsync() gibt ein Promise zurück, das sich zum Array-Instanz erfüllt.
  • Wenn Array.fromAsync() mit einem nicht-asynchronen Iterable-Objekt aufgerufen wird, wird jedes Element, das zum Array hinzugefügt werden soll, zuerst awaited.
  • Wenn ein mapFn bereitgestellt wird, wird dessen Ausgabe ebenfalls 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 erzeugt wird, nacheinander. Promise.all() wartet auf alle Werte gleichzeitig.
  • Array.fromAsync() iteriert das Iterable träge und holt nicht den nächsten Wert, bevor der aktuelle geklärt ist. Promise.all() holt alle Werte im Voraus und wartet auf sie 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]

Wenn items ein asynchrones Iterable ist, bei dem jeder Ergebniswert auch ein Promise ist, werden diese Promises ohne Awaiting dem resultierenden Array hinzugefügt. Dies ist konsistent mit dem Verhalten von for await...of.

js
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]

Hinweis: In der Praxis werden Sie selten ein asynchrones Iterable finden, das Promises liefert, da, wenn Sie es mit einer asynchronen Generatorfunktion implementieren, der yield-Ausdruck automatisch Promises entpackt.

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 mit einem synchronen Iterable

Wenn items ein synchrones Iterable oder array-ähnliches Objekt ist, werden sowohl der Eingang als auch die Ausgabe von mapFn 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]

Verwendung von mapFn mit einem asynchronen Iterable

Wenn items ein asynchrones Iterable ist, wird der Eingang zu mapFn nicht awaited, die Ausgabe jedoch schon. Unter Verwendung der gleichen Funktion createAsyncIter wie oben:

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

Interessanterweise bedeutet dies, dass Array.fromAsync(createAsyncIter()) nicht äquivalent zu Array.fromAsync(createAsyncIter(), (element) => element) ist, da letzteres jeden erzeugten Wert awaited, während ersteres dies nicht tut.

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

Vergleich mit Promise.all()

Array.fromAsync() wartet auf jeden Wert, der aus dem Objekt erzeugt wird, nacheinander. 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
})();

Schluss von synchronen Iterables bei Ablehnung

Ähnlich wie bei for await...of, wenn das Objekt, das iteriert wird, ein synchrones Iterable ist und ein erzeugtes Promise abgelehnt wird, wird die Methode return() des zugrunde liegenden Iterators aufgerufen, falls vorhanden, um dem Iterator zu ermöglichen, Bereinigungen vorzunehmen.

js
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

Spezifikationen

Spezifikation
ECMAScript® 2027 Language Specification
# sec-array.fromasync

Browser-Kompatibilität

Siehe auch