このページで解説している内容は、以下の YouTube 動画の解説で見ることができます。

【JavaScript入門】非同期処理とは

非同期処理とは

 ここでは、JavaScriptにおける「非同期処理」の概念と、その実装方法について解説します。JavaScriptは基本的にシングルスレッドで動作しますが、長い待機時間が必要な処理(例えば通信処理やタイマー処理)を実行する際に、処理がブロックされないよう「非同期処理」という仕組みが用いられます。これにより、ユーザーインターフェースの応答性を保ちながら、複数の処理を並行して進めることが可能となります。なお、Promiseやasync/awaitといった最新の非同期処理記述方法にも触れていきます。

1.非同期処理の基本概念

 JavaScriptでは、シングルスレッドの仕組みに加えて、待機が必要な処理を後回しにして実行する「非同期処理」が導入されています。例えば、一定時間後に特定の処理を実行するためのsetTimeout()は、非同期処理の代表例です。次の表は、シングルスレッド処理と非同期処理の特徴を比較したものです。

特徴シングルスレッド処理非同期処理
実行順序1つの処理が完了するまで次に進まず順番に実行待機中も次の処理に移り、完了時に登録済み関数を呼び出す。
ユーザビリティ待ち時間があると画面が固まる可能性がある待ち時間中でも他の処理が実行され、画面が応答する。

また、非同期処理を簡潔に書くためにPromiseやasync/awaitという仕組みが用いられます。

要素説明
Promise非同期処理の成功や失敗など、状態と結果を管理するオブジェクト。
async/awaitPromiseをより分かりやすい構文で扱うための仕組み。

2.サンプルプログラムによる非同期処理の実例と解説

 ここでは、簡単なsetTimeout()を利用した非同期処理の例を紹介します。サンプルプログラム「asyncProcessDemo.html」では、いくつかの処理を順に実行しつつ、setTimeout()で遅延実行される処理を組み合わせることで、非同期処理の仕組みを確認できます。以下のコードは、ページに簡単な説明文と共に、JavaScriptのconsole.log()により処理の実行順序を出力します。タイトルには絵文字を取り入れ、CSSでシンプルな装飾を施しています。

ファイル名: asyncProcessDemo.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>🚀 非同期処理入門</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      background: #eef;
      margin: 20px;
    }
    #container {
      padding: 20px;
      border: 2px solid #ccc;
      border-radius: 8px;
      background: #fff;
      text-align: center;
    }
    h1 {
      color: #3498db;
    }
  </style>
</head>
<body>
  <div id="container">
    <h1>🚀 非同期処理入門</h1>
    <p>このサンプルでは、setTimeout()を用いた非同期処理の基本的な動作を確認できます。</p>
    <p>※ コンソールの出力をご確認ください。</p>
  </div>
  <script>
    // メインの処理の開始
    console.log('処理1');
    console.log('処理2');
    
    // 非同期処理: 100ミリ秒後に実行される処理
    setTimeout(() => {
      console.log('処理3');
      console.log('処理4');
    }, 100);
    
    // メインの処理の継続
    console.log('処理5');
    console.log('処理6');
  </script>
</body>
</html>

2.1. 出力例の解説

ブラウザの出力例

このプログラムを実行すると、以下の順番でコンソールに出力されます。

デバックコンソールの出力

処理1
処理2
処理5
処理6
処理3
処理4

 最初に「処理1」と「処理2」が順次実行され、次にsetTimeout()で遅延していた処理が実行されるため、「処理5」と「処理6」が先に出力され、その後に「処理3」と「処理4」が出力されます。これにより、非同期処理が実際にどのように動作するかを確認できます。

2.2. ネストされた非同期処理の例

 実際の開発では、複数の非同期処理が連続して入れ子になる場合があります。下記の例は、setTimeout()を入れ子にした場合の例で、処理の順序がどのように連鎖するかを示しています。

ファイル名: asyncProcessSample.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>🚀 非同期ネストの例</title>
  <style>
    body { font-family: sans-serif; background: #f9f9f9; margin: 20px; }
    #info { padding: 20px; border: 1px dashed #888; text-align: center; }
  </style>
</head>
<body>
  <div id="info">
    <h2>非同期処理のネスト例</h2>
    <p>この例では、複数のsetTimeout()によって処理が入れ子になっています。コンソールの出力順にご注目ください。</p>
  </div>
  <script>
    console.log('処理A');
    // 100ミリ秒後に実行するネスト
    setTimeout(() => {
      console.log('処理B');
      setTimeout(() => {
        console.log('処理C');
        setTimeout(() => {
          console.log('処理D');
          setTimeout(() => {
            console.log('処理E');
          }, 100);
        }, 100);
      }, 100);
    }, 100);
    console.log('処理F');
  </script>
</body>
</html>

ブラウザの出力例

デバックコンソールの出力

処理A
処理F
処理B
処理C
処理D
処理E

 このように、非同期処理が入れ子になると、コードの可読性が低下する「コールバック・ヘル」の問題が発生します。そこで、Promiseやasync/awaitが導入され、非同期処理を平坦に記述できるようになりました。

3.非同期処理の意義と次章への展開

 非同期処理は、ユーザーインターフェースの応答性を確保するために非常に重要です。長い待機時間がある通信処理やファイル読み込みなどの処理を非同期にすることで、全体のパフォーマンスが向上します。また、Promiseやasync/awaitを利用することで、入れ子になった複雑な非同期処理をシンプルに記述できるようになります。今後の章では、Promiseの詳細やasync/awaitの使い方、さらにWeb Workerなどの非同期通信処理についても掘り下げていきます。

まとめ

 ここでは、「非同期処理とは何か」についてその基本概念と、setTimeout()を用いたシンプルなサンプルコードを通じて、処理の順序の違いを解説しました。

  • シングルスレッドなJavaScriptでは、各処理を順番に実行するため、重い処理があると全体がブロックされる可能性があります。
  • 非同期処理を利用することで、待機が必要な処理を後回しにし、他の処理を先に実行することができます。
  • Promiseやasync/awaitの導入により、よりシンプルで可読性の高い非同期処理の記述が可能となりました。

 この知識を基盤として、次のコンテンツではPromiseの詳細な使い方や、通信処理における非同期処理の実装方法について学んでいきます。