Signatur
Beschreibung
Array.fromAsync() ist das asynchrone Gegenstück zu Array.from(). Die Methode durchläuft ein asynchrones Iterable (z. B. einen async function*-Generator oder einen ReadableStream), ein normales Iterable oder ein array-ähnliches Objekt, wartet jeden Wert mit await ab und sammelt die Ergebnisse in einem neuen Array. Zurückgegeben wird ein Promise, das mit diesem Array erfüllt wird.
Im Kern ersetzt die Methode das übliche Muster const result = []; for await (const x of source) result.push(x); durch einen einzigen Ausdruck. Das ist besonders praktisch, wenn man z. B. Seiten einer paginierten API, Zeilen aus einem Stream oder Ergebnisse eines asynchronen Generators komplett einsammeln will.
Wichtig: Die Werte werden nacheinander verarbeitet, nicht gleichzeitig. Jeder Wert (und jedes Ergebnis von mapFn) wird abgewartet, bevor der nächste angefordert wird. Wer mehrere voneinander unabhängige Promises parallel auflösen will, ist mit Promise.all() meist besser bedient.
Ist items weder asynchron noch synchron iterierbar, wird es als array-ähnliches Objekt behandelt: Über die Indizes 0 bis length - 1 wird iteriert, und auch hier wird jeder Wert abgewartet.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $items Pflicht | AsyncIterable|Iterable|ArrayLike | Die Quelle, aus der das Array erstellt wird. Vorrang hat [Symbol.asyncIterator], danach [Symbol.iterator], zuletzt length plus Indizes. |
|
| $mapFn | (element: any, index: number) => any | undefined | Wird für jedes Element aufgerufen, nachdem es abgewartet wurde. Der Rückgabewert (auch ein Promise) wird ebenfalls abgewartet und landet im Ergebnis-Array. Anders als bei Array.prototype.map() erhält die Funktion nur element und index. |
| $thisArg | any | undefined | Wert, der beim Aufruf von mapFn als this verwendet wird. |
Rückgabewert
Promise, das mit dem neuen Array erfüllt wird. Es wird abgelehnt, wenn die Iteration, ein Element-Promise oder mapFn einen Fehler wirft bzw. ablehnt.Beispiele
Asynchronen Generator in ein Array umwandeln
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function* zaehle(bis) {
for (let i = 1; i <= bis; i++) {
await sleep(50);
yield i;
}
}
const zahlen = await Array.fromAsync(zaehle(5));
console.log(zahlen);
Paginierte API komplett einsammeln
// Liefert alle Einträge einer paginierten REST-API seitenweise
async function* ladeAlleSeiten(url) {
let naechste = url;
while (naechste) {
const res = await fetch(naechste);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { items, next } = await res.json();
yield* items;
naechste = next; // null, wenn keine weitere Seite existiert
}
}
try {
const benutzer = await Array.fromAsync(
ladeAlleSeiten('https://api.example.com/users?page=1'),
(u) => u.name
);
console.log(`${benutzer.length} Benutzer geladen`);
} catch (err) {
console.error('Laden fehlgeschlagen:', err.message);
}
Asynchrone mapFn mit Index
const ids = [101, 102, 103];
const ladeProdukt = async (id) => ({ id, preis: id * 1.5 });
// Das Promise aus mapFn wird automatisch abgewartet
const produkte = await Array.fromAsync(ids, async (id, index) => {
const p = await ladeProdukt(id);
return `${index + 1}. Produkt ${p.id}: ${p.preis} €`;
});
console.log(produkte);
Array-ähnliches Objekt mit Promises
const arrayLike = {
length: 3,
0: Promise.resolve('a'),
1: 'b',
2: new Promise((r) => setTimeout(() => r('c'), 100)),
};
const ergebnis = await Array.fromAsync(arrayLike);
console.log(ergebnis);
// Wichtig · Fallstricke
- Nacheinander statt parallel:
Array.fromAsync()wartet jedes Element einzeln ab. Bei einem Array bereits gestarteter Promises ist das Ergebnis zwar gleich, aber bei asynchronermapFnlaufen die Aufrufe hintereinander. Für echte ParallelitätPromise.all(items.map(fn))verwenden. - Unbehandelte Ablehnungen: Übergibt man ein synchrones Iterable von Promises und lehnt eines davon ab, bricht
Array.fromAsync()ab. Später ablehnende Promises werden dann nicht mehr beobachtet und können alsunhandledrejectionauftauchen.Promise.all()bzw.Promise.allSettled()verhalten sich hier robuster. - Kein Ersatz für unendliche Quellen: Bei endlosen asynchronen Iterables (z. B. Event-Streams ohne Ende) wird das Promise nie erfüllt, der Speicher wächst unbegrenzt.
- mapFn-Unterschied: Die Callback-Funktion erhält nur zwei Argumente (
element,index), nicht das Quell-Array. - Generisch: Wie
Array.from()kann die Methode übercallmit einem anderen Konstruktor alsthisaufgerufen werden, der dann das Ergebnisobjekt erzeugt. - Kompatibilität: Erst seit 2024 in allen großen Browsern verfügbar (Chrome/Edge 121, Firefox 115, Safari 16.4) sowie in Node.js ab Version 22 und Deno. Für ältere Umgebungen gibt es Polyfills (z. B.
core-js) oder man nutzt einefor await...of-Schleife. awaitauf oberster Ebene (Top-Level-Await) in den Beispielen funktioniert nur in ES-Modulen oder der Browser-Konsole.