🍬

ざっくり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