カテゴリ: JavaScript 更新日: 2025/10/11

JavaScriptのループと非同期処理の注意点を解説!初心者でもわかる使い方と落とし穴

JavaScriptのループと非同期処理の注意点を解説
JavaScriptのループと非同期処理の注意点を解説

先生と生徒の会話形式で理解しよう

生徒

「先生、JavaScriptでループを使って非同期の処理をするときに注意することはありますか?」

先生

「はい、JavaScriptのループと非同期処理は一緒に使うとちょっと難しい部分があります。特に順番やタイミングに気をつける必要がありますよ。」

生徒

「具体的にはどんな問題が起きるんですか?」

先生

「それでは、基本の仕組みとよくある注意点をわかりやすく説明しますね!」

1. JavaScriptの非同期処理とは?

1. JavaScriptの非同期処理とは?
1. JavaScriptの非同期処理とは?

非同期処理(ひどうきしょり)とは、「ある処理が終わるのを待たずに、次の処理を進めること」を言います。たとえば、ネットからデータを取ってくる処理は時間がかかるので、待っている間に他の処理を先に進められる仕組みです。

JavaScriptでは、この非同期処理を使ってプログラムの動きをスムーズにしています。

2. ループ処理と非同期処理が一緒に使われるときの問題

2. ループ処理と非同期処理が一緒に使われるときの問題
2. ループ処理と非同期処理が一緒に使われるときの問題

普通のループ処理は順番に1つずつ処理をしますが、非同期処理は終わる順番がバラバラになります。これが原因で、思った通りの順番で結果が得られなかったり、変数の値が期待と違ったりすることがあります。

たとえば、forループの中で非同期の関数を使うときに注意が必要です。

3. よくある問題例:変数のスコープと非同期処理

3. よくある問題例:変数のスコープと非同期処理
3. よくある問題例:変数のスコープと非同期処理

次の例を見てください。ループで変数iを使って非同期処理を呼んでいますが、意図した値が出ません。


for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}

実行結果は「3」「3」「3」となります。なぜでしょうか?

これは、varで宣言した変数のスコープ(有効範囲)が関係しています。varはループの外でも同じ変数を使うため、ループ終了後の値「3」がすべての非同期処理で使われてしまうのです。

4. 解決方法① letを使う

4. 解決方法① letを使う
4. 解決方法① letを使う

letはブロックスコープ({}内だけ有効な変数)なので、ループの各回ごとに別の変数として扱われます。これで問題を解決できます。


for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}

実行結果は「0」「1」「2」となり、期待通りです。

5. 解決方法② 即時関数(IIFE)を使う

5. 解決方法② 即時関数(IIFE)を使う
5. 解決方法② 即時関数(IIFE)を使う

古いJavaScriptでも対応できる方法として、即時実行関数(IIFE)があります。ループの中で即座に関数を呼び出して変数の値を閉じ込めます。


for (var i = 0; i < 3; i++) {
  (function(j) {
    setTimeout(() => {
      console.log(j);
    }, 100);
  })(i);
}

これも「0」「1」「2」と表示されます。

6. async/awaitでループの非同期処理を順番に実行する

6. async/awaitでループの非同期処理を順番に実行する
6. async/awaitでループの非同期処理を順番に実行する

JavaScriptのasyncawaitは、非同期処理を順番に書くときに便利です。awaitは非同期処理の完了を待つ意味です。


async function processArray(arr) {
  for (const item of arr) {
    await waitAndLog(item);
  }
}

function waitAndLog(value) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(value);
      resolve();
    }, 100);
  });
}

processArray([10, 20, 30]);

この例では、配列の値を順番に1つずつログに出しています。非同期でも順番が守られます。

7. 注意点:forEachはawaitと相性が悪い

7. 注意点:forEachはawaitと相性が悪い
7. 注意点:forEachはawaitと相性が悪い

forEachは内部で処理を繰り返すため、awaitを使っても全ての非同期処理が同時に走ってしまい、順番に処理できません。


const arr = [1, 2, 3];
arr.forEach(async (num) => {
  await waitAndLog(num);
});

順番に実行したい場合は、for...ofループを使いましょう。

8. まとめなしで最後にひとこと

8. まとめなしで最後にひとこと
8. まとめなしで最後にひとこと

JavaScriptのループと非同期処理は、一緒に使うときに変数のスコープや処理の順番に注意が必要です。letasync/awaitを上手に使って、正しく動くコードを書きましょう。

関連記事:
カテゴリの一覧へ
新着記事
New1
TypeScript
TypeScriptでパスエイリアスを設定する方法!baseUrlとpathsでコードをスッキリ整理
New2
JavaScript
JavaScriptのfor文の書き方を初心者向けにやさしく解説
New3
JavaScript
JavaScriptの関数でよくあるエラーとその解決法まとめ
New4
JavaScript
JavaScriptのイベント処理でよくあるエラーとその対処法
人気記事
No.1
Java&Spring記事人気No1
JavaScript
JavaScriptのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.2
Java&Spring記事人気No2
JavaScript
JavaScriptのマウスイベントの使い方(click, mouseoverなど)
No.3
Java&Spring記事人気No3
JavaScript
JavaScriptのtoStringとString関数の違いを初心者向けに解説
No.4
Java&Spring記事人気No4
JavaScript
JavaScriptの純粋関数(pure function)と副作用の違いを理解しよう
No.5
Java&Spring記事人気No5
JavaScript
JavaScriptプログラムの実行方法まとめ!ブラウザ・Node.js・コンソールの使い方
No.6
Java&Spring記事人気No6
JavaScript
JavaScriptで文字列をforループで1文字ずつ処理する方法!初心者向け解説
No.7
Java&Spring記事人気No7
TypeScript
TypeScriptの始め方:開発環境の構築手順【初心者向け】
No.8
Java&Spring記事人気No8
JavaScript
JavaScriptのDOMContentLoadedとloadイベントの違いを理解しよう