👻

[JavaScript] forEachでasync/awaitは使える

2022/08/23に公開

JavaScript の forEach で async/await は使える

JavaScrript の forEach で async/await が使えないという誤解が一部あるようですが、全く問題なく使えます。そういう誤解が何故発生してしまうかと言えば、非同期を同期させるための管理を行っていないからです。プログラムは思った通りではなく書いたとおりに動きます。同期させるようにプログラムを書かなければ、その通りの結果が返ってきます。使えないのではなく使っていないのが原因です。

forEach で非同期を同期させるプログラムを作る

配列の内容を 1 秒ごとに一つ表示させるプログラムを forEach で作ってみます。

  • こちらに実行環境を用意しました

https://www.typescriptlang.org/ja/play?#code/PTAEkTXQeeUboZD2GRVhkJUMhrBkBEMhohkJ0MhGhkB0MhThkB+GQS4YAoAYwHsA7AZwBdRaBTAWwEMAHAC0oCdmoALygAFKVCgANgEtWMxiICMAGgmgqAV2qLQABjWS+tYaGrMA7qACCfPuwCeAHlEBKYQD5QAN0oyAJh5uhqDsUlIA-ABcYu5CXr4BpHFeogDe6uzkAI6aMgIxbp7qkgDUpVo6oF6y8owAZPVmlqAACnyU8ixOiYGiogK0lFLezCmgxgB0nJq03APMQyNjriECUszsLIXjogC0e5WMERO0k3MyAGb0bhGTRTFhkfeuq5nhO54alNoNTeZWdqdGTdXpBBZLUa7J6mQbDKFvAC+rgA3KQKDQGKAODJqKYtg5qORYl8MpIqHRGCYRCwODx+Mw3CjQCBAKj6gAdTZAAJkAp3KAKDlAEkMgFoowBZ2oBNBnQgAsGQC6DIA7BnZgAMGQCKDIAyOUA6EqAcwZAPnagBkI9GSADaACJrEaVKAjQAhM0WgDCNqNABEjQBdSaXfgAUSy8wJRLE3nGZMkoQs7AUTEmWVy+UZqJZwDgSEA1QyAMoZAM8MgAmGAWAdI1ACEMYpK3zow2YkyklAA5qJA2iQ6Hw4wAW0Ol1GRD4WMvix6AAVOTMH43OHLc1KPQT17MkBKQBLnoBQ-UAJgxFs7rTYsJkJpOINNZgWAbDtAJEMhckyLRmTDEbOT03IEAFoqAMwZZYAhX0AYXICpfqClLMsV6tG5hqH8I1UVIRFzxxagmSAA

  • プログラム内容
// 疑似セマフォによるスケジューラ
const semaphore = (
  limit = 1,
  count = 0,
  rs = new Array<() => void>(),
  all?: () => void
) => ({
  acquire: () =>
    ++count > limit && new Promise<void>((resolve) => rs.push(resolve)),
  release: () => (--count ? rs.shift()?.() : all?.()),
  all: () => count && new Promise<void>((resolve) => (all = resolve)),
});

const main = async () => {
  const s = semaphore(); //引数に2以上を設定するとその数だけ並列で実行

  ["A", "B", "C", "D"].forEach(async (v) => {
    await s.acquire(); //セマフォカウントを増やす
    console.log(v);
    await new Promise((resolve) => setTimeout(resolve, 1000)); //1秒待つ
    s.release(); //セマフォカウントを減らす
  });

  await s.all(); //全ての終了を待つ
  console.log("end");
};

main();
  • 出力結果
A
B
C
D
end

ということで何の問題も無く順番通りに動作しました。

まとめ

JavaScript の forEach で async/await は使えます。

GitHubで編集を提案

Discussion