JavaScript:非同期(ネットワーク無しでも理解する)

投稿日:2026-01-13

音声

※ AI音声で読み上げます

目次

  1. 非同期とは?
  2. setTimeout/setIntervalで非同期を体感
  3. Promiseの基本(then/catch)
  4. async/awaitの書き方
  5. 例外処理(try/catch)との組み合わせ
  6. 並列実行(Promise.all)の考え方(軽く)
  7. 注意(ここだけ)
  8. 要約

非同期とは?

非同期(ひどうき)とは、「待ちが発生する処理を始めても、そこで止まらずに先へ進める」ことです。 たとえば「1秒待つ」「読み込みを待つ」のような処理は、終わるまで待っていると画面が固まってしまいます。 そこでJavaScriptは、待ちが必要な処理はいったん予約して、他の処理を先に進められるようにしています。

このページではネットワーク通信は使わず、setTimeout(あとで1回実行)と setInterval(一定間隔で繰り返し)を使って「予約 → 後から実行される」感覚を体験します。 その上で、Promise / then-catch / async-await によって「後から返ってくる結果」を きれいに扱う方法を学びます。

見るポイント:ログの順番です。ボタンを押した直後に出るログと、しばらくしてから出るログが混ざったら、 「待っている間も先に進めている(=非同期)」状態です。

デモ(このページでそのまま動きます)

ボタンを押して、#out と Console のログの「順番」を見てください。


      

setTimeout/setIntervalで非同期を体感

非同期は「いま実行せず、あとで実行する予約」です。

setTimeout は「1回だけ遅らせる予約」、setInterval は「一定間隔で繰り返す予約」です。

まずは ログの順番 に注目してください。ボタンを押した直後のログと、あとから出るログが混ざったら「非同期っぽさ」を掴めています。

観察ポイント:tick が何回出て、いつ止まるか。

Promiseの基本(then/catch)

Promiseは「将来の結果(成功 or 失敗)を表す箱」です。

then は成功した結果を受け取り、catch は失敗(reject)を受け取ります。

この小項目では「あとから届く結果を、後処理としてつなぐ」感覚を掴みます。

観察ポイント:700ms完了 then が後から出ること。

async/awaitの書き方

async/await は Promise を「上から順に読む」書き方にできます(同期っぽく見える)。

await は「ここで結果が出るまで待つ」ように見えますが、UI全体を止めるわけではありません。

thenチェーンが長くなると読みづらいので、順番が大事な処理は await が読みやすいです。

観察ポイント:async開始 →(少し待つ)→ awaitで待った:500ms の順番。

例外処理(try/catch)との組み合わせ

非同期の失敗は放置すると「どこで失敗したか」が見えづらくなります。

await する処理を try/catch で包むと、失敗理由をその場で拾えてデバッグが楽です。

この小項目では「reject(失敗)を catch で受け取る」流れを確認します。

観察ポイント:エラーが catchで受けた:失敗 になること。

並列実行(Promise.all)の考え方(軽く)

独立した非同期処理を同時に始めて全て終わるのを待つときにPromise.allを使います。個別にawaitするより高速になることが多く、結果は配列で返ります。要チェックとして、1つでもrejectすると全体がrejectになります。

最小コード:

<!-- HTML欄:CodePenのHTMLに貼ります -->
<button id="btn1">setTimeout/Interval</button>
<button id="btn2">Promise then/catch</button>
<button id="btn3">async/await</button>
<button id="btn4">try/catchでエラー</button>
<button id="btn5">Promise.all</button>
<pre id="out"></pre>
// JS欄
const out = document.getElementById('out');     // 画面にログを出す場所
const log = m => {                              // 観察用:Console + 画面に同じログを出す
  console.log(m);
  out.textContent += m + '\n';
};

function wait(ms){
  // 「ms ミリ秒たったら成功する Promise」を返す(= 待ちをPromise化)
  return new Promise(res => setTimeout(() => res(ms), ms));
}

document.getElementById('btn1').onclick = () => {
  log('setTimeout開始');                          // これはすぐ出る(同期的に実行)

  // 1秒後に実行を「予約」するだけ(今は止まらない)
  setTimeout(() => log('1秒後'), 1000);

  // 0.3秒ごとに繰り返し実行を予約(止めない限り tick が増える)
  const id = setInterval(() => log('tick'), 300);

  // 1.1秒後に interval を止める(clearIntervalしないと永遠に動く)
  setTimeout(() => { clearInterval(id); log('interval停止'); }, 1100);
};

document.getElementById('btn2').onclick = () => {
  // wait(700) は「700ms後に成功するPromise」
  // then:成功したときに後から実行される/catch:失敗したとき
  wait(700)
    .then(ms => log(ms + 'ms完了 then'))
    .catch(e => log('thenエラー:' + e));
};

document.getElementById('btn3').onclick = async () => {
  log('async開始');                                 // これはすぐ出る

  // await:Promiseの完了を「待つ」ように見えるが、UI/他の処理は止めない
  const v = await wait(500);

  log('awaitで待った:' + v + 'ms');                 // 完了後に続きが実行される
};

document.getElementById('btn4').onclick = async () => {
  try{
    // 400ms後にわざと失敗(reject)させるPromise
    await new Promise((_, rej) =>
      setTimeout(() => rej(new Error('失敗')), 400)
    );
  }catch(e){
    // await中の失敗は try/catch で受け取れる(非同期でも理由が追える)
    log('catchで受けた:' + e.message);
  }
};

document.getElementById('btn5').onclick = () => {
  // Promise.all:複数のPromiseを「同時に開始」して、全部終わったら then が1回だけ動く
  Promise.all([wait(300), wait(600)])
    .then(a => log('Promise.all完了:' + a.join(',')));
};

貼り付け場所は、CodePenならHTML欄にHTMLを、JS欄にJSを貼ります。ローカルでは<body>内にHTMLを置き、<script>でJSを読み込む形にします。

実行方法は、ページを開いて各ボタンを押すと#outとConsoleにログが出ます。期待どおりのタイミングやエラー表示が確認できればOKです。

確認方法は、#outに順にログが出ることと、Consoleにも同じログが出ることを見ます。

よくあるミスは、HTMLの要素IDとJSの参照を合わせ忘れることです。その場合はonclickが未定義になりやすいので、DOMContentLoadedで初期化するかIDを一致させます。

使い分けの基準は、順次処理はasync/awaitが読みやすく、短いチェーンはthen/catchでもよいです。独立処理の同時実行はPromise.allを使い、繰り返しは状況に応じてsetIntervalか逐次setTimeoutを選びます。

注意(ここだけ)

  • setTimeout の順序は「待ち時間が短い順に即実行」ではなく、キューの都合で前後します。ログで順序を確認しながら学ぶのが安全です。

  • async/await でも例外は起きます。非同期処理は try/catch で包まないと「落ちた理由」が見えづらくなります。

  • 並列(Promise.all)は一つでも失敗すると全体が失敗扱いになります。必要なら個別に失敗を吸収する設計にします。

要約

  • setTimeoutは遅延実行で、setIntervalは繰り返し実行ですが、どちらもUIをブロックしません。
  • Promiseは非同期の結果を表し、then/catchで処理を繋げます。
  • async/awaitでPromiseを同期風に書けるため、可読性が上がります。
  • awaitとtry/catchを組み合わせると、自然な例外処理ができます。
  • Promise.allで並列実行して効率化できますが、1つの失敗で全体が失敗します。