
公式ドキュメントページが何たるかはわかってきた
ここにforEach()関数のすべて?が掲載されているみたい。
またもや意味不明領域、、、
// ここから別物
const ratings = [5, 4, 5];
let sum = 0;
const sumFunction = async (a, b) => a + b;
ratings.forEach(async (rating) => {
sum = await sumFunction(sum, rating);
});
console.log(sum);
// 本来期待される出力: 14
// 実際の出力: 0
意味わからんにAIくんの意味はうっすら分かる解説
これはJavaScriptの**非同期処理(async/await)**と、forEachの仕様が組み合わさった時に非常によく起こる「落とし穴」ですね。
結論から言うと、forEachは「待ってくれない」からです。
なぜ 14 にならないのか?
- forEach は投げっぱなし:forEach は、中の関数が async(非同期)であっても、その完了を待たずに次のループへ進み、さらにその後の処理(console.log)を実行してしまいます。
- 実行のタイミング:sumFunction が計算を終えて結果を返す前に、JavaScriptは一番下の console.log(sum) を実行してしまいます。その時点ではまだ sum は初期値の 0 のままなので、 0 が表示されます。
どうすれば解決できる?
非同期処理を順番に待ちたい(同期させたい)場合は、forEach ではなく for...of ループ を使うのが最も一般的なショートハンド的な解決策です。
修正コード:for...of を使う
JavaScript
const ratings = [5, 4, 5];
let sum = 0;
const sumFunction = async (a, b) => a + b;
// 非同期の文脈(async関数内など)で実行する必要があります
const calculate = async () => {
for (const rating of ratings) {
sum = await sumFunction(sum, rating); // ここでちゃんと待機する
}
console.log(sum); // 出力: 14
};
calculate();
もう一つの解決策:reduce を使う(上級編)
配列の値を一つにまとめたい場合、reduce を使うのがプロっぽい書き方です。ただし、非同期が絡むと少し複雑になります。
JavaScript
const total = await ratings.reduce(async (accPromise, rating) => {
const acc = await accPromise;
return await sumFunction(acc, rating);
}, Promise.resolve(0));
console.log(total); // 出力: 14
まとめ
forEachは**「並列でどんどん実行して、終わりを待たない」**時に使う。awaitを使って順番に処理したいならfor...ofを使う。
「非同期処理」はJavaScriptの中でも少しややこしい部分ですが、ここをマスターすると一気に書けることの幅が広がります。
この for...of の書き方について、もっと詳しく知りたい部分はありますか?
分からん!けど100日後もしくは365日後には分かるはず
さっぱり分からん。けどうっっっっすら分かった、覚えたことがある
- forEach()は配列を拾い出すためのもの。配列が対象
- 同期処理(ピタゴラスイッチ)ではなく非同期処理(待ってくれないJavaScriptの処理)
- forEach()が読みたいコードに出てきたら悩んだ後AIに翻訳してもらおう
- ここでもアロー関数が出現。アロー関数が頭に100%馴染んでないからそこで解読ストップしちゃう
コメントを残す