NodeJS 速習チュートリアル

Node.js イベントループ

1. イベントループとは?

イベントループ(Event Loop)は、Node.jsがノンブロッキングかつ効率的であるための核心となるメカニズムです。

Node.jsは、タスクをオペレーティングシステム(OS)に委譲し、その結果を**コールバック(Callback)を通じて処理することで、単一のスレッド(Thread)**でありながら数千もの同時接続を管理することを可能にしています。

2. イベントループの仕組み

Node.jsは、以下のステップに従って操作を処理します。

  1. メインスクリプトの実行(同期コード)
  2. マイクロタスク(Microtasks)の処理(Promises, process.nextTick)
  3. タイマー(Timers)の実行(setTimeout, setInterval)
  4. I/Oコールバックの実行(ファイルシステム、ネットワーク操作など)
  5. setImmediateコールバックの実行
  6. クローズイベント(Close events)の処理(socket.on('close') など)

2.1 例:イベントループの実行順序

以下のコードを実行して、処理の順番を確認してみましょう。

console.log('1番目:同期処理');

setTimeout(() => console.log('3番目:タイマー'), 0);

Promise.resolve().then(() => console.log('2番目:プロミス(マイクロタスク)'));

console.log('4番目:同期処理(最後)');

この例では、以下の順序で実行されます:

  1. 同期コードが最初に実行されます('1番目', '4番目')。
  2. 次のフェーズに移る前にマイクロタスク(Promises)が実行されます('2番目')。
  3. 最後にタイマーが実行されます('3番目')。

3. イベントループの各フェーズ

イベントループは、以下の順序で異なる種類のコールバックを処理します。

  • Timers(タイマー): setTimeoutsetInterval の期限が切れたコールバックを実行。
  • I/O Callbacks: 完了したI/O操作のコールバックを実行。
  • Poll(ポーリング): 新しいI/Oイベントを取得。
  • Check(チェック): setImmediate のコールバックを実行。
  • Close(クローズ): クリーンアップに関するコールバック(例:socket.on('close'))。
各フェーズの間で、Node.jsはマイクロタスク(Promises)と process.nextTick のコールバックを実行します。

3.1 例:フェーズごとの優先順位

console.log('1. 開始');

// Next tick キュー(最も優先度が高い)
process.nextTick(() => console.log('2. Next tick'));

// マイクロタスクキュー (Promise)
Promise.resolve().then(() => console.log('3. Promise'));

// タイマーフェーズ
setTimeout(() => console.log('4. Timeout'), 0);

// チェックフェーズ
setImmediate(() => console.log('5. Immediate'));

console.log('6. 終了');

出力結果:

1. 開始
6. 終了
2. Next tick
3. Promise
4. Timeout
5. Immediate

この結果は、同期コード > nextTick > Promises > Timers > Checkフェーズ という優先順位を示しています。

4. なぜイベントループが重要なのか?

イベントループにより、Node.jsはシングルスレッドで数千の同時接続を処理できるため、以下の用途に最適です。

  • リアルタイムアプリケーション
  • API およびマイクロサービス
  • データストリーミング
  • チャットアプリケーション

5. まとめ

  • Node.jsは非同期操作を処理するためにイベントループを使用します。
  • コールバックの種類によって実行の優先順位が異なります。
  • マイクロタスク(Promises)は、次のイベントループフェーズに進む前に実行されます。
  • このノンブロッキングモデルにより、高い並行処理性能が実現されています。