async/awaitとforEachループを併用してPromiseの結果を取り出す
forEachループでasync/awaitを使用することに問題はありますか?ファイルの配列をループして、各ファイルの内容を待ち受けようとしています。
import fs from 'fs-promise' async function printFiles () { const files = await getFilePaths() // Assume this works fine files.forEach(async (file) => { const contents = await fs.readFile(file, 'utf8') console.log(contents) }) } printFiles()
このコードは動作しますが、何か問題があるのでしょうか?このような高次関数ではasync/awaitを使ってはいけないと誰かに言われたので、何か問題があるのかどうかを聞きたかったのです。
回答
確かにこのコードは動作しますが、あなたが期待していることをしていないのは確かです。複数の非同期呼び出しを行っていますが、printFiles関数はその後すぐに戻ります。
ファイルを順番に読みたい場合は、forEachを使ってはいけません。代わりに現代的な for ... of ループを使えば、 await は期待通りに動作します。
async function printFiles () { const files = await getFilePaths(); for (const file of files) { const contents = await fs.readFile(file, 'utf8'); console.log(contents); } }
並行してファイルを読みたい場合は、forEachを確かに使うことはできません。非同期コールバック関数の呼び出しはそれぞれプロミスを返しますが、それを待つのではなく捨てています。代わりにmapを使えば、Promise.allで得られるプロミスの配列を待ち受けることができます。
async function printFiles () { const files = await getFilePaths(); await Promise.all(files.map(async (file) => { const contents = await fs.readFile(file, 'utf8') console.log(contents) })); }
https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop