DEV Community

Cover image for Node.js Event Loop
Kavitha Megalingam
Kavitha Megalingam

Posted on

Node.js Event Loop

Node.js is a single-threaded, non-blocking runtime environment, which means that functions are delegated to the event loop. An event loop is an endless loop that awaits tasks, completes them, and then sleeps until additional tasks are received.

Image description

The event loop comprises three components:

  • Call stack
  • Callback queue
  • Micro-task queue

Call Stack

Node.js uses a system called the call stack to keep track of the functions that the script calls. When a function call occurs, it is added to the top of the call stack, and when the function ends, it is removed from the call stack. This is known as the LIFO pattern. If an asynchronous event happens, the event loop adds it to the appropriate callback queue.

Callback Queue

The callbacks that are registered on the call stack are kept in the callback queue. The callback queue follows the FIFO principle. There are six phases in the event loop, each of which is a callback queue. The timer phase, pending phase, idle/prepare phase, poll phase, check phase, and closing phase are these phases.

Image description

1. Timer Phase:

In this phase, callbacks for expired intervals and timeouts are executed. If there are any expired timers, the event loop starts executing them in ascending order until the timer is empty. The execution of the timer is controlled by the poll phase of the event loop.

2. Pending Phase:

The execution of system-related callbacks occurs in this stage. Sometimes, while the OS is being processed, callbacks wait for the job to be finished; these callback types are placed in the pending phase.

3. Idle/Prepare:

In this phase, the event loop does nothing. It is idle and prepares to go to the next phase.

4. Poll phase:

This is an important phase in the event loop that registers a callback from the asynchronous event. Here, two things will happen.

  • The event loop begins executing callbacks synchronously if the poll phase is not empty, and it continues doing so until the queue is empty or a system-dependent hard limit is reached.

  • Either of the following scenarios will take place if the poll queue is empty:

a. First scenario:

  • If any callback is scheduled by setImmediate(), then the event loop ends the poll phase and will move on to the next phase, which is the check phase, to execute those callbacks.
  • If there is no callback scheduled by setImmediate(), then the event loop waits for the callbacks to be added to the poll queue and executes them immediately.

b. Second Scenario:
The event loop will determine whether any timers are set to expire during the timer phase if the poll queue is empty. The event loop will jump directly from the poll phase to the timer phase if one or more timers are ready.

5. Check Phase

In this stage, setImmediate() callbacks are executed. When there are no callbacks in the poll phase, the event loop moves this phase.

6. Closing Phase

Callbacks associated with closing events, such as socket.on('close') or process.exit(), is executed by the event loop in this phase.

Microtask Queue

The microtask queue is similar to the callback queue, but here only callbacks that are created by microtasks are registered. Microtasks are callbacks that are created by process.nextTick(), promise.then(), and catch() methods. process.nextTick() has precedence over all other microtasks. Microtask queue are always executed when the event loop completes one tick or one trip. Once the microtask queue is completed, the event loop continues its execution from the timer phase.

Oldest comments (0)