🎞️

JavaScriptのイベントループをGIFアニメーションで理解する

2024/04/07に公開

はじめに

この記事の内容は、以下の動画でも解説しています。こちらも是非ご覧ください!

https://youtu.be/Ro3q1i-19bc?si=jDoAPc8BYqd333dS

イベントループの定義

イベントループとは、非同期処理の管理や実行を行うための仕組みのことです。

...と言っても、いきなりイベントループについて説明すると難しいと思うので、まずは非同期処理を復習しましょう!

JavaScriptの非同期処理の復習

非同期処理とは、前の処理が終わるのを待たずに次の処理を行う方法のことです。

例えば、いくつかの作業があるとします。

非同期処理は、1番目の作業をした後、2番目の作業を "裏側" で実行させて、その間に3番目の作業を進めます。そして、2番目の作業が終わったら完了が通知される、という流れになります。

詳細は、以下の動画で解説しているので、気になる人はぜひ見てみてください。

https://www.youtube.com/watch?v=wl_oOMFa1MM

イベントループとは

先ほど、非同期処理の流れは、『1番目の作業をした後、2番目の作業を "裏側" で実行させて、その間に3番目の作業を進める』という説明をしました。この "裏側" とはいったいどこなのか、疑問に思った人もいるかもしれません。

実はこの "裏側" を理解するためには、ブラウザ環境について知っておく必要があります。なので、これらからブラウザ環境について説明していこうと思います!

ブラウザ環境

ブラウザ環境は大まかに、4つの要素で構成されています。これから1つずつ解説していきます。

コールスタック

1つ目はコールスタックです。これは、V8 などの JavaScript エンジンの一部であり、 現在実行中の関数を追跡するための仕組みのことです。

例えば、以下のような簡単なコードがあったとして、コールスタックがどのように追跡するのか見てみましょう。

function function2() {
  console.log("Hello");
}
function function1() {
  function2();
}
function1();

まず最初に function1 が実行されると、コールスタックに function1 が追加されます。

次に、 function1 の中を見てみると、 function2 が実行されているので、コールスタックの中には function2 が追加されます。

そして、 function2 の中を見に行くと、 console.log が実行されているので、コールスタックの中には console.log が追加されます。

その後、console.log の処理が終わると、コールスタックから console.log は削除され、同様に、 function2function1 も取り除かれます。

このように、コールスタックは実行中の関数を追跡し、どの関数が現在実行されているのかを把握する役割を果たします。

Web API

2つ目の要素は Web API です。Web API はブラウザが提供する様々な機能のことです。

例えば、以下のような機能があります。

  • setTimeout
  • fetch
  • Promise
  • DOM

これらの機能は V8 などの JavaScript エンジンからは完全に切り離されていて、"ブラウザ自体" が処理を行います。

タスクキュー

3つ目の要素はタスクキューです。 タスクキューはその名の通り、実行待ちのタスクが格納されるキューのことです。

キューとはデータ構造の一つで、一番最初に入れたタスクが、一番最初に取り出される、いわば "先入れ先出し" の仕組みを持っています。

イベントループ

4つ目の要素はイベントループです。イベントループとは、タスクキューに入っているタスクを順番に処理していく仕組みのことです。

例えるなら "監視人" のようなもので、コールスタックの中身を監視して、中身が無くなったタイミングで、タスクキューから一番古いタスクを取り出して実行します。

と言っても、このままだとイメージしづらいと思うので、ここまで紹介した4つの要素を組み合わせて、イベントループがどのように動いているのか解説していきます。

イベントループの挙動

ブラウザ環境の4つの要素を組み合わせた全体像は、以下のようになります。

左上がコールスタック、右上が Web API、真ん中がイベントループ、一番下がタスクキューです。

以下のコードを例に、ブラウザ環境でどのように処理されるのか見てみましょう。

console.log("1");

setTimeout(() => {
  console.log("3");
}, 5000)

console.log("2");

まず最初に実行されるのは console.log("1") なので、コールスタックに console.log("1") が追加されます。そして、処理が終わるとコールスタックから削除されます。

次に実行されるのは、setTimeout です。これも、先ほど同様、コールスタックに追加されます。

setTimeout は、先ほど説明した通り、Web API の一部なので、setTimeout の引数に渡されたコールバック関数が Web API に投げられます。

すると、Web API の中でタイマーが起動して、指定された時間だけ待つことになります。そして、タイマーが起動した後は、setTimeout 自体はコールスタックから削除されます。

次に実行されるのは console.log("2") なので、コールスタックに console.log("2") が追加されます。そして、処理が終わるとコールスタックから削除されます。

そうこうしている間に、先ほどタイマーに指定した5秒が経過しましたね!タイマーが完了すると、Web API は、タスクキューにコールバック関数を追加します。

ここで、ようやくイベントループの出番です。イベントループは、定期的にコールスタックを監視して、コールスタックが空になったことを感知すると、タスクキューから次のタスクを取り出して、コールスタックに追加します。

そして、最後に、コールバック関数の実行が終わると、コールスタックが空になり、すべてのコード実行が終了します。

さいごに

以上で、イベントループの解説は終わりです!

他にもいくつか記事を書いているので、読んでみてください!

参考

Discussion