ざっくりEvent Loopを理解する
はじめに
JavaScriptで非同期処理を理解するにあたって、必ず理解しておきたいのが、Event Loop。Event Loopの処理の中にはいろんなステップがあるようですが、その説明はとりあえず省いて、まずEvent Loopとはなんぞやというところを簡潔に理解したい。
参照した記事
全体図
参照した記事の中の図の方がわかりやすいと思います笑
イベントループを説明する前に知っておくべき用語
- Call Stack
- Web APIs
- Async Callbacks
- Task Queue
- Microtask Queue
Call Stack
実行コンテキスト。実行する関数を挿入したり、削除したりして、関数を置いておくプログラム。
しかし、前の実行が終わらないと次の実行に行かない(blocking)ため、Async Callbacks (非同期コールバック) が必要になってくる。
Web APIs
DOM (document), ajax (XMLHttpRequest), setTimeoutなどのapiは、V8エンジンには含まれておらず、ブラウザが提供している。
Async Callbacks (非同期コールバック)
非同期関数(例:setTimeout, fetch, addEventListenerなど)が呼び出されると、その処理自体はCall Stack上ですぐ終わり、コールバック関数はWeb API環境で実行待ちになります。その後、処理が完了したタイミングでコールバックがtask queueに登録されます。
当たり前だけど、そういう意味でコールバックは「呼び戻す」ということなんだ!
え、でも誰の何が、また呼び戻してきてくれるの?
それが、the Event Loop。
Task Queue
ブラウザが任意の時間待って、勝手に実行をしてしまうと、call stackで実行していた関数に割入ってしまう可能性があります。それを防ぐために、task queueに関数を置いておきます。
Microtask Queue
Promiseなどの非同期処理は、microtask queueと呼ばれる別のキューに入ります。
本題
the Event Loop
Node.jsで使われているlibuvというC++のライブラリが提供する、the Event Loop。ブラウザ環境では、各ブラウザごとに異なるイベントループの実装が使われていますが、基本的な動作原理は同じです。
簡単にいうと、イベントループの仕事は、call stackとtask queueを観察することです。
call stackが空になった時に、task queueに置いておいた関数をcall stackに挿入し、実行します。
また、microtask queueの中の関数は、task queueの実行よりも優先されます。そのため、microtask queueをすべて処理してから、task queue内の関数が実行されていきます。
しかし、それで全て解決するわけではない。
重い処理を同期処理でしてしまうと、call stackにその関数がずっと置いたまま、task queueに置いて関数がいつまでも実行されないままになってしまう。
イベントループを止めないようなプログラムを書こう。
Discussion