Javascript 非同期処理について


はじめに

非同期処理とはそもそもどのようなことを行うのかを初学者の方が見てもわかるようにまとめてみました。
まずは非同期処理を理解するためには、同期処理との違いについて把握しなくてはなりません。

違い

1つの処理が完了するまで次の処理に進まないというのが同期処理です。
※webサイトへアクセスした際、重い処理がある場合にはその処理の完了を待たないと次の処理を行うことができません。
対して非同期処理とは、並行して同時に処理が可能です。

Javascriptの実行場所について

Javascrtiptは、メインスレッドという領域で実行されます。
メインスレッドは、Javascriptの実行とその結果によってレンダリング(再描画、表示の更新)を行う領域です。

※ここでのレンダリングは、ビュー全体を再読み込むする形ではなく、関数の実行によってDOMの一部を操作するイメージです。
具体的には、下記のような形です。

同期処理は、実行中の関数がこのメインスレッドを占有し、その処理が完了するまで他の処理を行うことができません。
この点が同期処理では、同時に処理が行えない理由となります。

具体的には下記のコードです。


function blockTime(timeout) { 
  const startTime = Date.now();
  // `timeout`ミリ秒経過するまで無限ループをする
  while (true) {
      const diffTime = Date.now() - startTime;
      if (diffTime >= timeout) {
          return; // 指定時間経過したら関数の実行を終了
      }
  }
}
console.log("処理を開始");
blockTime(5000); // 他の処理を5000ミリ秒の間、メインスレッドを占有します。
console.log("5秒経過したので出力します。");

下記のような形になります。

※下記動画が非同期処理について非常にわかりやすく説明されてます。素晴らしい動画です。
web万屋エンジニアさんの非同期処理について

非同期処理

非同期処理もメインスレッド上で実行されますが、複数の処理を同時に実行することができます。

※非同期処理も同期処理と同様に呼び出された順番で実行されますが、別の非同期処理の完了を待たずに次の処理を行うことができる点が同期通信とは異なります。
ですが、他の関数と同時に実行されるという訳ではありません。
例えば、他の同期処理が先にメインスレッドを占有していればその処理が終わるまでは処理が実行されません。

今回は非同期処理を行うためのAPIであるsetTimeoutを用いて実装します。

<button id="eventBtn">btn</button>
window.addEventListener("load", ()=>{

  function blockTime(timeout) { 
    const startTime = Date.now();
    // `timeout`ミリ秒経過するまで無限ループをする
    while (new Date() - startTime < timeout);
    console.log("block done");
  }

  setTimeout(function(){
    console.log("2秒経過したのでコールバックします")
    blockTime(3000)
  },2000);

  document.getElementById("eventBtn").addEventListener("click", () => {
    console.log("clicked");
  });

})

上記コードを実行すると以下のようになります。
①setTimeout関数に渡したblockTimeは非同期処理として、メインスレッドから切り離される。(blockTimeout関数は2秒後に実行されます。)
②setTimeout関数によって2秒間はメインスレッドが空くため、他の処理が並行して行うことができます。
③blockTime関数がコールバックされるとメインスレッドは占有される。
④blockTimeが完了すると他の処理を実行することができます。

処理のイメージです。

まとめ

Javascriptはメインスレッドで実行されていることがわかりました。
非同期処理は、メインスレッドから切り離されるためその間同時に処理が同時に実行が可能ということですね。

参考資料

Javascriptの非同期処理演習