Node.js animated: Event Loop Phases
Tags: javascript, node, beginners, webdev
Published: 2022-11-19 20:52:26

In the previous article, [Node.js animated: Event Loop](https://dev.to/nodedoctors/an-animated-guide-to-nodejs-event-loop-3g62), you explored how Libuv and the event loop enable asynchronous task handling in Node.js' single-threaded environment. We simplified the event loop as a mechanism that pushes callbacks from a **single event queue** to an empty call stack. In reality, the event loop is composed of multiple phases, each responsible for specific asynchronous tasks.


![event_loop_phases](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkc1k3qhlvj0hrts6ud3.gif)

## The event loop phases

> A phase is a FIFO queue of callbacks to execute. When the event loop enters a given phase, it executes callbacks until the queue is exhausted or the maximum number of callbacks is run and moves to the next stage.

The event loop has **6** phases, and they run in the following order:

- **Timers**: executes callbacks scheduled by setTimeout() and setInterval().
- **Pending callbacks**: executes I/O callbacks deferred to the next loop iteration.
- **Idle-prepare**: only used internally.
- **Poll**: retrieve new I/O events and execute I/O-related callbacks
- **Check**: executes callbacks scheduled by setImmediate().
- **Close callbacks**: some close callbacks, e.g., socket.on('close', …).


![event_loop_phases_handled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/332ug2w37qhov5fgvbv4.gif)


The event loop doesn’t constantly keep spinning. If there are no active I/O handlers and the event loop doesn’t need to process any callbacks, the Node.js program automatically exits. On the other hand, the event loop stops on the poll phase to capture incoming requests whenever you create a web server and the phases are empty.

## Timers and check phase

You are ready to apply your newly acquired knowledge. Still, you can be disappointed when running a `setTimeout` after a `setImmediate`, or vice versa, because the result is not deterministic.

`setTimeout` schedules a callback after **at least** the defined milliseconds have elapsed. The CPU could be busy and Libuv is unable to set the task as complete before the event loop processes the timer phase. Consequently, the setImmediate callback could be run in advance, although the timer is the first phase.

In this example, the CPU is not busy, and the `setTimeout` callback is immediately added to its dedicated queue before `setImmedate`.

{% embed https://vimeo.com/772833707?autoplay=1&loop=1&autopause=0 %}

In this second example, the event loop starts processing the timer phase, but the timer has not expired yet, so setImmediate callback is run in advance.

{% embed https://vimeo.com/772834525?autoplay=1&loop=1&autopause=0 %}

## Exploring the poll phase

You are now wondering how I can test the phases processing order. The following code snippet will help you prove the order of the phases.


![poll_phase](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rjla2set11e20tt5k9v9.png)

Once Node.js starts the program, the event loop processes all the queues and blocks on the poll phase waiting for incoming requests. When someone makes a GET HTTP request to the server, the event loop goes through these steps:

1. The event loop pushes the request handler on the call stack.
2. A `setImmediate` callback is added in the **check** phase.
3. A `setTimeout` callback is scheduled in the **timers** phase.
4. The event loop moves to the check phase. The `setImmediate` callback is popped off from the queue and pushed on the call stack for execution.
5. The event loop does not move any callbacks from empty queues.
6. The `setTimeout` callback is popped off from the timer queue and pushed on the call stack for processing.

{% embed https://vimeo.com/772860074?autoplay=1&loop=1&autopause=0 %}

The code is available at:

[Animated Node.js-02-event-loop-phases repository](https://github.com/fabrilallo/animated-nodejs/tree/main/02-event-loop-phases)

## Conclusion

Now, you understand the event loop and its phases. You can also tell the difference between `setTimeout` and `setImmediate` and expect a non-deterministic behavior when running them in sequence. In addition, you know that event loop blocks on the poll phase waiting for new I/O requests on a Node.js web server.

But where are promises handled in Node.js?

You will explore it in more detail in the following articles.

## Resources

- [Node.js official documentation: The Node.js Event Loop, Timers, and process.nextTick()](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/)
- [Libuv event loop source code](https://github.com/libuv/libuv/blob/v1.x/src/unix/core.c#L384)


_If you liked the article, follow us on Twitter [@fabrizio.lallo](https://twitter.com/FabriLallo) and [@AndrewHu368](https://twitter.com/AndrewHu368)_