🦔for await of を使うとEslintに怒られるから、Promise.all()を使う2021/11/05に公開2021/12/304件TypeScriptESLinttechDiscussionpetamoriken2021/11/07いくつか気になる点がありますので指摘させてください。 for-await-of について JavaScript には Iterable と呼ばれるインターフェースがあり、それを満たしているものについてはスプレッド構文や for-of を使ってループ処理をすることが出来ます。配列はそれを満たしているものの一つです。 https://ja.javascript.info/iterable const arr = [1, 2, 3, 4]; // スプレッド構文でコピーを作る const copy = [...arr]; console.log(copy); // [1, 2, 3, 4] console.log(arr === copy); // false // for-of でループする for (const val of arr) { console.log(val); // 1, 2, 3, 4 } 一方で AsyncIterable というインターフェースもあります。Iterable では値を順に取り出す際に全て同期的に取得することが出来ましたが、逆に全て非同期に取得する場合がこちらです。イメージとしては動画のストリーミング再生で、決まった順番のものを少しずつ取得しにいくような感じでしょうか。こちらは for-await-of でループ処理をします。 最初の悪い例として for-await-of を使われていますが、配列は Iterable ですので for-of と勘違いされているかと思います(Iterable から AsyncIterable へ変換可能なため for-await-of が使えてしまっていますが、普通はそうしません)。 for (const userData of USER_DATA_LIST) { await createUser(userData.userId, userData.userName); } Promise について JavaScript の Promise は作った時点で非同期の処理が実行されています。つまり Async Function を実行した時点で既にその処理は走っています。 何故 ESLint がループ内の await を禁止し Promise.all を使うことを勧めるかというと、前者だと直列に、後者だと並行に実行されることになるからです(前者はまさしく AsyncIterable と同じことをしています)。同時に並行に実行できるものはなるべくそうしたほうがパフォーマンスが良くなるため Promise.all を使うことを勧めているわけです。 Promise.all()は、非同期関数の配列を受け取ります。そこで、データ元の配列をmapしつつ、非同期関数を返すようにすることで、スマートに非同期処理の繰り返し実行が可能となります。 いずれかの関数で、errorがThrowされると、それ移行の実行していない関数は実行せず終了します。 つまりこれは誤りです。非同期函数(Async Function)の配列ではなく、非同期函数が実行されその結果を待つ Promise の配列を受け取ります。あくまで全てが成功した、もしくは一つ失敗したタイミングをはかるためのものであって、他のものが実行されなかったり中断されるようなことはありません。 イミュータブルについて イミュータブルは不変という意味です。そもそも変更できないものについて使われる言葉です。 https://developer.mozilla.org/ja/docs/Glossary/Immutable スプレッド構文で、イミュータブルにするのも忘れずに。 スプレッド構文ではあくまでコピーを作っているだけですので、イミュータブルという言葉は使われません。 また配列の Array#map というメソッドは配列から新しい配列を作るものになっているため、ここにスプレッド構文はなくていいかなと思います。 Promise.all( USER_DATA_LIST.map(userData => createUser(userData.userId, userData.userName)) ) 指摘は以上となります。技術記事を書くことはとても素晴らしいことだと思うのでこれからも是非続けていってください。以下の記事が役に立つかもしれません。読んでいただきありがとうございました。 https://zenn.dev/uhyo/articles/technical-articles takeru04302021/11/07貴重なご意見ありがとうございます。 改めて調べ直しまして、お手数かと思いますが、不明な点について質問させていただきます。 お時間ありましたらご回答いただきたいです。 また、いただきましたご指摘をもとに、記事の方更新しよう思います。 for-await-of について MDNのドキュメントを改めて確認しましたが、 for await (variable of iterable) { statement } とありますように、ただの配列でも理論上は、動作可能かと理解していました。また、Eslint実行外では、通常に動作しているという認識でこれまで使用していました。 暗黙的に、IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか? ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のようにfor ofで記述することが可能、ということで僕の理解正しいでしょうか? async () => { for (const userData of USER_DATA_LIST) { await createUser(userData.userId, userData.userName) } } 上記の書き方が可能であり正の場合は、僕が記事内で提示している悪い例は、僕が勘違いで書いていますので、訂正させていただきます。 Promise.allについて こちらも改めてMDNを確認させていただきました。 MDNの文章中には、 拒否の場合 渡されたプロミスのいずれかが拒否された場合、Promise.all は、他のプロミスが解決したかどうかに関わらず、拒否されたプロミスの値で非同期的に拒否されます。 とあるように、確かにご指摘の通り、渡されたプロミスという言葉が使われているので、関数ではなくPromiseが渡されていること理解できました。 この時、 他のプロミスが解決したかどうかに関わらず というのは、Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか? イミュータブルについて こちらについては、Array.mapに関して僕が仕様を勘違いしていました。 新しい配列を返す場合は、あえてコピーを作成する必要はないですね。 記事内で訂正させていただきました。 返信遅れましたが、ご確認お願いします。 petamoriken2021/11/08に更新 for-await-of について 暗黙的に、IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか? JavaScript の言語仕様である ECMAScript に記述されています。JavaScript エンジン内部で暗黙的に使われている内部オペレーションの GetIterator にて、第二引数の hint に async を指定した際 CreateAsyncFromSyncIterator が使われていることが確認できます(for-await-of で使われます)。 https://tc39.es/ecma262/#sec-getiterator ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のようにfor ofで記述することが可能、ということで僕の理解正しいでしょうか? はい for-of で記述することが可能です。非同期函数の中の話なので同期的な実行と言えるのかわからないところですが、少なくともその函数は最初に await に到達するまでは同期的に実行されると言えると思います(非同期函数は await 式を使っていない部分は全て同期的に実行されます)。 Iterable に for-await-of を使用した場合については MDN にも記載されていますが、イテレーターリザルトの値が Promise だった場合に違いがあるものになっています。USER_DATA_LIST に Promise が含まれない今回の例では for-of も for-await-of も結果としては違いはないですね。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_sync_iterables_and_generators Promise.allについて Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか? その通りです。以下のコードを実行してみるとわかりやすいかもしれません。 // 全て成功(fullfilled) Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]).then((result) => { console.log(result); // [1, 2, 3] }).catch((error) => { console.log(error); // 呼ばれない }); // 一つ失敗(rejected) Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.reject(new Error("error")), ]).then((result) => { console.log(result); // 呼ばれない }).catch((error) => { console.log(error); // Error("error") }); なお余談ですが非同期関数内では Promise.all に対しても await することが出来ます。個人的には Promise#then や Promise#catch メソッドを使うよりはこちらを使いますね。 (async () => { try { const result = await Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]); console.log(result); // [1, 2, 3] } catch (error) { console.log(error); // この例だと呼ばれない } })(); JavaScript の非同期処理全般については以下の連載記事がかなり詳しいです。入門記事へのリンクもありますので確認してみてください。 https://zenn.dev/qnighy/articles/345aa9cae02d9d takeru04302021/11/08すべての質問に対してご丁寧に対応いただきましてありがとうございます! アウトプットのリスクとして、この記事を閲覧した人に勘違いを与えてしまう可能性がにはあることを改めて認識できました。 より、詳細にドキュメントを調べてから、アウトプットをしていこうと思います! そもそもの前提として、for await ofがEslintに怒られる原因だと勘違いしていましたが、非同期処理を同期的に繰り返す行為そのものに対して、Eslintは怒ってくれてたということですね。。 そういう意味では、脳死でPromise.allを使おうという方針自体が間違っていると思いますので、この記事の修正をさせていただこうと思います。 改めまして、こんな記事でも丁寧に対応いただきまして本当にありがとうございます。 返信を追加
petamoriken2021/11/07いくつか気になる点がありますので指摘させてください。 for-await-of について JavaScript には Iterable と呼ばれるインターフェースがあり、それを満たしているものについてはスプレッド構文や for-of を使ってループ処理をすることが出来ます。配列はそれを満たしているものの一つです。 https://ja.javascript.info/iterable const arr = [1, 2, 3, 4]; // スプレッド構文でコピーを作る const copy = [...arr]; console.log(copy); // [1, 2, 3, 4] console.log(arr === copy); // false // for-of でループする for (const val of arr) { console.log(val); // 1, 2, 3, 4 } 一方で AsyncIterable というインターフェースもあります。Iterable では値を順に取り出す際に全て同期的に取得することが出来ましたが、逆に全て非同期に取得する場合がこちらです。イメージとしては動画のストリーミング再生で、決まった順番のものを少しずつ取得しにいくような感じでしょうか。こちらは for-await-of でループ処理をします。 最初の悪い例として for-await-of を使われていますが、配列は Iterable ですので for-of と勘違いされているかと思います(Iterable から AsyncIterable へ変換可能なため for-await-of が使えてしまっていますが、普通はそうしません)。 for (const userData of USER_DATA_LIST) { await createUser(userData.userId, userData.userName); } Promise について JavaScript の Promise は作った時点で非同期の処理が実行されています。つまり Async Function を実行した時点で既にその処理は走っています。 何故 ESLint がループ内の await を禁止し Promise.all を使うことを勧めるかというと、前者だと直列に、後者だと並行に実行されることになるからです(前者はまさしく AsyncIterable と同じことをしています)。同時に並行に実行できるものはなるべくそうしたほうがパフォーマンスが良くなるため Promise.all を使うことを勧めているわけです。 Promise.all()は、非同期関数の配列を受け取ります。そこで、データ元の配列をmapしつつ、非同期関数を返すようにすることで、スマートに非同期処理の繰り返し実行が可能となります。 いずれかの関数で、errorがThrowされると、それ移行の実行していない関数は実行せず終了します。 つまりこれは誤りです。非同期函数(Async Function)の配列ではなく、非同期函数が実行されその結果を待つ Promise の配列を受け取ります。あくまで全てが成功した、もしくは一つ失敗したタイミングをはかるためのものであって、他のものが実行されなかったり中断されるようなことはありません。 イミュータブルについて イミュータブルは不変という意味です。そもそも変更できないものについて使われる言葉です。 https://developer.mozilla.org/ja/docs/Glossary/Immutable スプレッド構文で、イミュータブルにするのも忘れずに。 スプレッド構文ではあくまでコピーを作っているだけですので、イミュータブルという言葉は使われません。 また配列の Array#map というメソッドは配列から新しい配列を作るものになっているため、ここにスプレッド構文はなくていいかなと思います。 Promise.all( USER_DATA_LIST.map(userData => createUser(userData.userId, userData.userName)) ) 指摘は以上となります。技術記事を書くことはとても素晴らしいことだと思うのでこれからも是非続けていってください。以下の記事が役に立つかもしれません。読んでいただきありがとうございました。 https://zenn.dev/uhyo/articles/technical-articles takeru04302021/11/07貴重なご意見ありがとうございます。 改めて調べ直しまして、お手数かと思いますが、不明な点について質問させていただきます。 お時間ありましたらご回答いただきたいです。 また、いただきましたご指摘をもとに、記事の方更新しよう思います。 for-await-of について MDNのドキュメントを改めて確認しましたが、 for await (variable of iterable) { statement } とありますように、ただの配列でも理論上は、動作可能かと理解していました。また、Eslint実行外では、通常に動作しているという認識でこれまで使用していました。 暗黙的に、IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか? ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のようにfor ofで記述することが可能、ということで僕の理解正しいでしょうか? async () => { for (const userData of USER_DATA_LIST) { await createUser(userData.userId, userData.userName) } } 上記の書き方が可能であり正の場合は、僕が記事内で提示している悪い例は、僕が勘違いで書いていますので、訂正させていただきます。 Promise.allについて こちらも改めてMDNを確認させていただきました。 MDNの文章中には、 拒否の場合 渡されたプロミスのいずれかが拒否された場合、Promise.all は、他のプロミスが解決したかどうかに関わらず、拒否されたプロミスの値で非同期的に拒否されます。 とあるように、確かにご指摘の通り、渡されたプロミスという言葉が使われているので、関数ではなくPromiseが渡されていること理解できました。 この時、 他のプロミスが解決したかどうかに関わらず というのは、Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか? イミュータブルについて こちらについては、Array.mapに関して僕が仕様を勘違いしていました。 新しい配列を返す場合は、あえてコピーを作成する必要はないですね。 記事内で訂正させていただきました。 返信遅れましたが、ご確認お願いします。 petamoriken2021/11/08に更新 for-await-of について 暗黙的に、IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか? JavaScript の言語仕様である ECMAScript に記述されています。JavaScript エンジン内部で暗黙的に使われている内部オペレーションの GetIterator にて、第二引数の hint に async を指定した際 CreateAsyncFromSyncIterator が使われていることが確認できます(for-await-of で使われます)。 https://tc39.es/ecma262/#sec-getiterator ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のようにfor ofで記述することが可能、ということで僕の理解正しいでしょうか? はい for-of で記述することが可能です。非同期函数の中の話なので同期的な実行と言えるのかわからないところですが、少なくともその函数は最初に await に到達するまでは同期的に実行されると言えると思います(非同期函数は await 式を使っていない部分は全て同期的に実行されます)。 Iterable に for-await-of を使用した場合については MDN にも記載されていますが、イテレーターリザルトの値が Promise だった場合に違いがあるものになっています。USER_DATA_LIST に Promise が含まれない今回の例では for-of も for-await-of も結果としては違いはないですね。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_sync_iterables_and_generators Promise.allについて Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか? その通りです。以下のコードを実行してみるとわかりやすいかもしれません。 // 全て成功(fullfilled) Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]).then((result) => { console.log(result); // [1, 2, 3] }).catch((error) => { console.log(error); // 呼ばれない }); // 一つ失敗(rejected) Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.reject(new Error("error")), ]).then((result) => { console.log(result); // 呼ばれない }).catch((error) => { console.log(error); // Error("error") }); なお余談ですが非同期関数内では Promise.all に対しても await することが出来ます。個人的には Promise#then や Promise#catch メソッドを使うよりはこちらを使いますね。 (async () => { try { const result = await Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]); console.log(result); // [1, 2, 3] } catch (error) { console.log(error); // この例だと呼ばれない } })(); JavaScript の非同期処理全般については以下の連載記事がかなり詳しいです。入門記事へのリンクもありますので確認してみてください。 https://zenn.dev/qnighy/articles/345aa9cae02d9d takeru04302021/11/08すべての質問に対してご丁寧に対応いただきましてありがとうございます! アウトプットのリスクとして、この記事を閲覧した人に勘違いを与えてしまう可能性がにはあることを改めて認識できました。 より、詳細にドキュメントを調べてから、アウトプットをしていこうと思います! そもそもの前提として、for await ofがEslintに怒られる原因だと勘違いしていましたが、非同期処理を同期的に繰り返す行為そのものに対して、Eslintは怒ってくれてたということですね。。 そういう意味では、脳死でPromise.allを使おうという方針自体が間違っていると思いますので、この記事の修正をさせていただこうと思います。 改めまして、こんな記事でも丁寧に対応いただきまして本当にありがとうございます。 返信を追加
takeru04302021/11/07貴重なご意見ありがとうございます。 改めて調べ直しまして、お手数かと思いますが、不明な点について質問させていただきます。 お時間ありましたらご回答いただきたいです。 また、いただきましたご指摘をもとに、記事の方更新しよう思います。 for-await-of について MDNのドキュメントを改めて確認しましたが、 for await (variable of iterable) { statement } とありますように、ただの配列でも理論上は、動作可能かと理解していました。また、Eslint実行外では、通常に動作しているという認識でこれまで使用していました。 暗黙的に、IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか? ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のようにfor ofで記述することが可能、ということで僕の理解正しいでしょうか? async () => { for (const userData of USER_DATA_LIST) { await createUser(userData.userId, userData.userName) } } 上記の書き方が可能であり正の場合は、僕が記事内で提示している悪い例は、僕が勘違いで書いていますので、訂正させていただきます。 Promise.allについて こちらも改めてMDNを確認させていただきました。 MDNの文章中には、 拒否の場合 渡されたプロミスのいずれかが拒否された場合、Promise.all は、他のプロミスが解決したかどうかに関わらず、拒否されたプロミスの値で非同期的に拒否されます。 とあるように、確かにご指摘の通り、渡されたプロミスという言葉が使われているので、関数ではなくPromiseが渡されていること理解できました。 この時、 他のプロミスが解決したかどうかに関わらず というのは、Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか? イミュータブルについて こちらについては、Array.mapに関して僕が仕様を勘違いしていました。 新しい配列を返す場合は、あえてコピーを作成する必要はないですね。 記事内で訂正させていただきました。 返信遅れましたが、ご確認お願いします。
petamoriken2021/11/08に更新 for-await-of について 暗黙的に、IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか? JavaScript の言語仕様である ECMAScript に記述されています。JavaScript エンジン内部で暗黙的に使われている内部オペレーションの GetIterator にて、第二引数の hint に async を指定した際 CreateAsyncFromSyncIterator が使われていることが確認できます(for-await-of で使われます)。 https://tc39.es/ecma262/#sec-getiterator ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のようにfor ofで記述することが可能、ということで僕の理解正しいでしょうか? はい for-of で記述することが可能です。非同期函数の中の話なので同期的な実行と言えるのかわからないところですが、少なくともその函数は最初に await に到達するまでは同期的に実行されると言えると思います(非同期函数は await 式を使っていない部分は全て同期的に実行されます)。 Iterable に for-await-of を使用した場合については MDN にも記載されていますが、イテレーターリザルトの値が Promise だった場合に違いがあるものになっています。USER_DATA_LIST に Promise が含まれない今回の例では for-of も for-await-of も結果としては違いはないですね。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_sync_iterables_and_generators Promise.allについて Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか? その通りです。以下のコードを実行してみるとわかりやすいかもしれません。 // 全て成功(fullfilled) Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]).then((result) => { console.log(result); // [1, 2, 3] }).catch((error) => { console.log(error); // 呼ばれない }); // 一つ失敗(rejected) Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.reject(new Error("error")), ]).then((result) => { console.log(result); // 呼ばれない }).catch((error) => { console.log(error); // Error("error") }); なお余談ですが非同期関数内では Promise.all に対しても await することが出来ます。個人的には Promise#then や Promise#catch メソッドを使うよりはこちらを使いますね。 (async () => { try { const result = await Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]); console.log(result); // [1, 2, 3] } catch (error) { console.log(error); // この例だと呼ばれない } })(); JavaScript の非同期処理全般については以下の連載記事がかなり詳しいです。入門記事へのリンクもありますので確認してみてください。 https://zenn.dev/qnighy/articles/345aa9cae02d9d
takeru04302021/11/08すべての質問に対してご丁寧に対応いただきましてありがとうございます! アウトプットのリスクとして、この記事を閲覧した人に勘違いを与えてしまう可能性がにはあることを改めて認識できました。 より、詳細にドキュメントを調べてから、アウトプットをしていこうと思います! そもそもの前提として、for await ofがEslintに怒られる原因だと勘違いしていましたが、非同期処理を同期的に繰り返す行為そのものに対して、Eslintは怒ってくれてたということですね。。 そういう意味では、脳死でPromise.allを使おうという方針自体が間違っていると思いますので、この記事の修正をさせていただこうと思います。 改めまして、こんな記事でも丁寧に対応いただきまして本当にありがとうございます。
Discussion
いくつか気になる点がありますので指摘させてください。
for-await-ofについてJavaScript には
Iterableと呼ばれるインターフェースがあり、それを満たしているものについてはスプレッド構文やfor-ofを使ってループ処理をすることが出来ます。配列はそれを満たしているものの一つです。一方で
AsyncIterableというインターフェースもあります。Iterableでは値を順に取り出す際に全て同期的に取得することが出来ましたが、逆に全て非同期に取得する場合がこちらです。イメージとしては動画のストリーミング再生で、決まった順番のものを少しずつ取得しにいくような感じでしょうか。こちらはfor-await-ofでループ処理をします。最初の悪い例として
for-await-ofを使われていますが、配列はIterableですのでfor-ofと勘違いされているかと思います(IterableからAsyncIterableへ変換可能なためfor-await-ofが使えてしまっていますが、普通はそうしません)。PromiseについてJavaScript の
Promiseは作った時点で非同期の処理が実行されています。つまり Async Function を実行した時点で既にその処理は走っています。何故 ESLint がループ内の
awaitを禁止しPromise.allを使うことを勧めるかというと、前者だと直列に、後者だと並行に実行されることになるからです(前者はまさしくAsyncIterableと同じことをしています)。同時に並行に実行できるものはなるべくそうしたほうがパフォーマンスが良くなるためPromise.allを使うことを勧めているわけです。つまりこれは誤りです。非同期函数(Async Function)の配列ではなく、非同期函数が実行されその結果を待つ
Promiseの配列を受け取ります。あくまで全てが成功した、もしくは一つ失敗したタイミングをはかるためのものであって、他のものが実行されなかったり中断されるようなことはありません。イミュータブルについて
イミュータブルは不変という意味です。そもそも変更できないものについて使われる言葉です。
スプレッド構文ではあくまでコピーを作っているだけですので、イミュータブルという言葉は使われません。
また配列の
Array#mapというメソッドは配列から新しい配列を作るものになっているため、ここにスプレッド構文はなくていいかなと思います。指摘は以上となります。技術記事を書くことはとても素晴らしいことだと思うのでこれからも是非続けていってください。以下の記事が役に立つかもしれません。読んでいただきありがとうございました。
貴重なご意見ありがとうございます。
改めて調べ直しまして、お手数かと思いますが、不明な点について質問させていただきます。
お時間ありましたらご回答いただきたいです。
また、いただきましたご指摘をもとに、記事の方更新しよう思います。
for-await-ofについてMDNのドキュメントを改めて確認しましたが、
とありますように、ただの配列でも理論上は、動作可能かと理解していました。また、Eslint実行外では、通常に動作しているという認識でこれまで使用していました。
暗黙的に、
IterableからAsyncIterableへ変換されてしまうという記述はMDNを参照したところ見つかりませんでした。どのドキュメントを参照されたのでしょうか?ご教授いただきたいのですが、例えばあるデータの配列をもとに繰り返し処理を実行したい場合(かつ同期的に実行したい場合)は、以下のように
for ofで記述することが可能、ということで僕の理解正しいでしょうか?上記の書き方が可能であり正の場合は、僕が記事内で提示している悪い例は、僕が勘違いで書いていますので、訂正させていただきます。
Promise.allについてこちらも改めてMDNを確認させていただきました。
MDNの文章中には、
とあるように、確かにご指摘の通り、渡されたプロミスという言葉が使われているので、関数ではなく
Promiseが渡されていること理解できました。この時、
というのは、
Promise.allでは、Catchされた以外のPromiseがどうなっているのかを把握することができないということで理解正しいでしょうか?イミュータブルについて
こちらについては、
Array.mapに関して僕が仕様を勘違いしていました。新しい配列を返す場合は、あえてコピーを作成する必要はないですね。
記事内で訂正させていただきました。
返信遅れましたが、ご確認お願いします。
for-await-ofについてJavaScript の言語仕様である ECMAScript に記述されています。JavaScript エンジン内部で暗黙的に使われている内部オペレーションの
GetIteratorにて、第二引数の hint に async を指定した際CreateAsyncFromSyncIteratorが使われていることが確認できます(for-await-ofで使われます)。はい
for-ofで記述することが可能です。非同期函数の中の話なので同期的な実行と言えるのかわからないところですが、少なくともその函数は最初にawaitに到達するまでは同期的に実行されると言えると思います(非同期函数はawait式を使っていない部分は全て同期的に実行されます)。Iterableにfor-await-ofを使用した場合については MDN にも記載されていますが、イテレーターリザルトの値がPromiseだった場合に違いがあるものになっています。USER_DATA_LISTにPromiseが含まれない今回の例ではfor-ofもfor-await-ofも結果としては違いはないですね。Promise.allについてその通りです。以下のコードを実行してみるとわかりやすいかもしれません。
なお余談ですが非同期関数内では
Promise.allに対してもawaitすることが出来ます。個人的にはPromise#thenやPromise#catchメソッドを使うよりはこちらを使いますね。JavaScript の非同期処理全般については以下の連載記事がかなり詳しいです。入門記事へのリンクもありますので確認してみてください。
すべての質問に対してご丁寧に対応いただきましてありがとうございます!
アウトプットのリスクとして、この記事を閲覧した人に勘違いを与えてしまう可能性がにはあることを改めて認識できました。
より、詳細にドキュメントを調べてから、アウトプットをしていこうと思います!
そもそもの前提として、
for await ofがEslintに怒られる原因だと勘違いしていましたが、非同期処理を同期的に繰り返す行為そのものに対して、Eslintは怒ってくれてたということですね。。そういう意味では、脳死で
Promise.allを使おうという方針自体が間違っていると思いますので、この記事の修正をさせていただこうと思います。改めまして、こんな記事でも丁寧に対応いただきまして本当にありがとうございます。