Array.fromAsync()
Baseline 2024Newly 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, flachkopierte Array
-Instanz aus einem asynchronen Iterator, Iterator oder einem array-ähnlichen Objekt.
Syntax
Array.fromAsync(items)
Array.fromAsync(items, mapFn)
Array.fromAsync(items, mapFn, thisArg)
Parameter
items
-
Ein asynchroner Iterator, Iterator oder array-ähnliches Objekt, das in ein Array konvertiert werden soll.
mapFn
Optional-
Eine Funktion, die auf jedes Element des Arrays aufgerufen wird. Wenn übergeben, wird jeder zu dem Array hinzuzufügende Wert zuerst durch diese Funktion geleitet, und der Rückgabewert von
mapFn
wird stattdessen dem Array hinzugefügt (nachdem er awaitet wurde). Die Funktion wird mit den folgenden Argumenten aufgerufen:element
-
Das aktuell im Array verarbeitete Element. Wenn
items
ein synchroner Iterator oder ein array-ähnliches Objekt ist, werden zuerst alle Elemente awaitet, undelement
wird niemals ein thenable sein. Wennitems
ein asynchroner Iterator ist, wird jeder erzeugte Wert so übergeben, wie er ist. index
-
Der Index des aktuell im Array verarbeiteten Elements.
thisArg
Optional-
Wert, der als
this
beim Ausführen vonmapFn
verwendet wird.
Rückgabewert
Beschreibung
Array.fromAsync()
ermöglicht die Erstellung von Arrays aus:
- asynchronen Iterator-Objekten (Objekte wie
ReadableStream
undAsyncGenerator
); oder, falls das Objekt nicht asynchron iterierbar ist, - iterierbaren Objekten (Objekte wie
Map
undSet
); oder, falls das Objekt nicht iterierbar ist, - array-ähnlichen Objekten (Objekte mit einer
length
-Eigenschaft und indizierten Elementen).
Array.fromAsync()
iteriert den asynchronen Iterator auf eine Weise, die for await...of
sehr ähnlich ist. Array.fromAsync(items)
entspricht im Allgemeinen dem folgenden Code, wenn items
ein asynchroner oder synchroner Iterator ist:
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 in folgenden Punkten:
Array.fromAsync()
verarbeitet asynchrone Iterator-Objekte.Array.fromAsync()
gibt einenPromise
zurück, der sich in die Array-Instanz erfüllt.- Wenn
Array.fromAsync()
mit einem nicht-asynchronen Iterator-Objekt aufgerufen wird, wird jedes hinzuzufügende Element zuerst awaitet. - Wenn eine
mapFn
bereitgestellt wird, wird deren Ausgabe ebenfalls intern awaited.
Array.fromAsync()
und Promise.all()
können beide einen Iterator von Promises in einen Promise eines Arrays umwandeln. Es gibt jedoch zwei wesentliche Unterschiede:
Array.fromAsync()
wartet jeden Wert ab, der aus dem Objekt nacheinander erzeugt wird.Promise.all()
wartet alle Werte gleichzeitig ab.Array.fromAsync()
iteriert den Iterator faul 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 Iterator
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 asynchroner Iterator ist, bei dem jeder Ergebniswert ebenfalls ein Promise ist, dann werden diese Promises dem resultierenden Array hinzugefügt, ohne awaited zu werden. Dies entspricht dem Verhalten von 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]
Hinweis:
In der Praxis werden Sie selten einen asynchronen Iterator finden, der Promises erzeugt, da, wenn Sie ihn mit einer asynchronen Generatorfunktion implementieren, der yield
-Ausdruck automatisch Promises entpackt.
Array aus einem synchronen Iterator
Array.fromAsync(
new Map([
[1, 2],
[3, 4],
]),
).then((array) => console.log(array));
// [[1, 2], [3, 4]]
Array aus einem synchronen Iterator, der Promises erzeugt
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
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 Iterator
Wenn items
ein synchroner Iterator oder ein array-ähnliches Objekt ist, werden sowohl die Eingabe als auch die Ausgabe von mapFn
intern von Array.fromAsync()
awaited.
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 Iterator
Wenn items
ein asynchroner Iterator ist, wird die Eingabe an mapFn
nicht awaited, aber die Ausgabe wird awaited. Verwenden Sie dieselbe createAsyncIter
-Funktion wie oben:
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.
Array.fromAsync(createAsyncIter(), (element) => element).then((array) =>
console.log(array),
);
// [1, 2, 3]
Vergleich mit Promise.all()
Array.fromAsync()
wartet jeden Wert ab, der aus dem Objekt nacheinander erzeugt wird. Promise.all()
wartet alle Werte gleichzeitig ab.
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 Iteratoren
Ähnlich wie bei for await...of
, wenn das zu iterierende Objekt ein synchroner Iterator ist und ein Fehler beim Iterieren auftritt, wird die return()
-Methode des zugrunde liegenden Iterators nicht aufgerufen, sodass der Iterator nicht geschlossen wird.
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);
}
})();
// caught Error: error
// 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
.
(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 # sec-array.fromAsync |