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.
構文
Array.fromAsync(arrayLike)
Array.fromAsync(arrayLike, mapFn)
Array.fromAsync(arrayLike, mapFn, thisArg)
引数
返値
解説
Array.fromAsync()
により、以下のものから配列を作成することができます。
- 非同期反復可能オブジェクト(
ReadableStream
やAsyncGenerator
などのオブジェクト)、または、オブジェクトが非同期反復可能ではない場合、 - 反復可能オブジェクト(
Map
やSet
等のオブジェクト)、または、オブジェクトが反復可能ではない場合、 - 配列風オブジェクト(
length
プロパティとインデックス値による要素を持つオブジェクト)。
Array.fromAsync()
は for await...of
にとてもよく似た方法で非同期反復可能オブジェクトを反復処理します。 Array.fromAsync()
は、以下をの点除いて Array.from()
とほぼ同じ動きをします。
Array.fromAsync()
は非同期反復可能オブジェクトを扱うことができます。Array.fromAsync()
は配列インスタンスで履行されるPromise
を返します。Array.fromAsync()
が非同期反復可能オブジェクトを指定して呼び出された場合、配列に追加する各要素が最初に待機されます。mapFn
が指定された場合、入出力を内部的に待機します。
Array.fromAsync()
と Promise.all()
はどちらも、反復可能なプロミスを配列のプロミスに変換することができます。しかし、 2 つの重要な違いがあります。
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]
同期反復可能オブジェクトから配列を取得
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 の使用
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]
Promise.all() との比較
Array.fromAsync()
はオブジェクトから得られる値を順番に待ちます。 Promise.all()
はすべての値を同時に待ちます。
function* makeAsyncIterable() {
for (let i = 0; i < 5; i++) {
yield new Promise((resolve) => setTimeout(resolve, 100));
}
}
(async () => {
console.time("Array.fromAsync() time");
await Array.fromAsync(makeAsyncIterable());
console.timeEnd("Array.fromAsync() time");
// Array.fromAsync() time: 503.610ms
console.time("Promise.all() time");
await Promise.all(makeAsyncIterable());
console.timeEnd("Promise.all() time");
// Promise.all() time: 101.728ms
})();
同期反復可能オブジェクトのエラー処理なし
for await...of
と同様に、反復処理されるオブジェクトが同期反復可能オブジェクトで、反復処理中にエラーが発生した場合、基盤となるイテレーターの return()
メソッドは呼び出されず、イテレーターは閉じられません。
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
イテレーターを閉じる必要がある場合は、代わりに for...of
ループを使用して、各値を await
する必要があります。
(async () => {
const arr = [];
try {
for (const val of generatorWithRejectedPromises()) {
arr.push(await val);
}
} catch (e) {
console.log("caught", e);
}
})();
// called finally
// caught 3
仕様書
Specification |
---|
ES Array.fromAsync (2022) # sec-array.fromAsync |
ブラウザーの互換性
BCD tables only load in the browser