このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
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.
Array.fromAsync() は静的メソッドで、非同期反復可能オブジェクト、反復可能オブジェクト、配列風のオブジェクトから、シャローコピーされた新しい配列インスタンスを作成します。
In this article
構文
Array.fromAsync(items)Array.fromAsync(items, mapFn)Array.fromAsync(items, mapFn, thisArg)引数
items配列に変換する非同期反復可能、反復可能、配列風オブジェクトです。
mapFn省略可配列の各要素に対して呼び出す関数です。指定された場合は、配列に追加するすべての値が最初にこの関数に渡され、
mapFnの返値が(待機後に)配列に追加されます。この関数は以下の引数で呼び出されます。thisArg省略可mapFn実行時にthisとして使用する値です。
返値
解説
Array.fromAsync() により、以下のものから配列を作成することができます。
- 非同期反復可能オブジェクト(
ReadableStreamやAsyncGeneratorなどのオブジェクト)、または、オブジェクトが非同期反復可能ではない場合、 - 反復可能オブジェクト(
MapやSet等のオブジェクト)、または、オブジェクトが反復可能ではない場合、 - 配列風オブジェクト(
lengthプロパティとインデックス値による要素を持つオブジェクト)。
Array.fromAsync() はfor await...of にとてもよく似た方法で非同期反復可能オブジェクトを反復処理します。Array.fromAsync(items) は、以下をの点除いてArray.from() とほぼ同じ動きをします。
const result = [];for await (const element of items) { result.push(element);}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]items が非同期の反復可能オブジェクトであり、それぞれの結果のvalue もプロミスである場合、それらのプロミスは待機されることなく、結果の配列に追加されます。これは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]メモ:実際には、プロミスを生成する非同期反復可能オブジェクトに遭遇することはほとんどありません。なぜなら、非同期ジェネレータ関数を使用して実装すると、yield 式によってプロミスが自動的にラップ解除されるからです。
同期反復可能オブジェクトから配列を取得
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 を同期反復可能オブジェクトと使用
items が同期反復可能オブジェクトまたは配列風である場合、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]mapFn を非同期反復可能オブジェクトと使用
items が非同期反復可能オブジェクトの場合、mapFn への入力は待機されませんが、出力は待機されます。上記と同じcreateAsyncIter 関数を使用します。
Array.fromAsync(createAsyncIter(), async (element) => (await element) * 2).then( (array) => console.log(array),);// [2, 4, 6]興味深いことに、これはArray.fromAsync(createAsyncIter()) はArray.fromAsync(createAsyncIter(), (element) => element) と同等ではないことを意味しています。後者はそれぞれの生成値を待機しますが、前者は待機しないからです。
Array.fromAsync(createAsyncIter(), (element) => element).then((array) => console.log(array),);// [1, 2, 3]Promise.all() との比較
Array.fromAsync() はオブジェクトから得られる値を順番に待ちます。Promise.all() はすべての値を同時に待ちます。
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})();同期反復可能オブジェクトのエラー処理なし
for await...of と同様に、反復処理されるオブジェクトが同期反復可能オブジェクトで、反復処理中にエラーが発生した場合、基盤となるイテレーターのreturn() メソッドは呼び出されず、イテレーターは閉じられません。
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イテレーターを閉じる必要がある場合は、代わりに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> # sec-array.fromAsync> |