JavaScriptのイベントループをGIFアニメーションで理解する
イベントループの定義
イベントループとは、非同期処理の管理や実行を行うための仕組みのことです。
...と言っても、いきなりイベントループについて説明すると難しいと思うので、まずは非同期処理を復習しましょう!
JavaScriptの非同期処理の復習
非同期処理とは、前の処理が終わるのを待たずに次の処理を行う方法のことです。
例えば、いくつかの作業があるとします。
非同期処理は、1番目の作業をした後、2番目の作業を "裏側" で実行させて、その間に3番目の作業を進めます。そして、2番目の作業が終わったら完了が通知される、という流れになります。
詳細は、以下の動画で解説しているので、気になる人はぜひ見てみてください。
イベントループとは
先ほど、非同期処理の流れは、『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
は削除され、同様に、 function2
と function1
も取り除かれます。
このように、コールスタックは実行中の関数を追跡し、どの関数が現在実行されているのかを把握する役割を果たします。
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