What is the Event Loop?
The event loop is what allows NodeJS to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.
Since most modern kernels are multi-threaded, they can handle multiple operations executing in the background. When one of these operations completes, the kernel tells NodeJS so that the appropriate callback may be added to the poll-queue to eventually be executed.
Event Loop Explained
When Node.js starts, it initializes the event loop, processes the provided input script which may make async API calls, schedule timers, or call process.nextTick(), then begins processing the event loop.

Each phase has a FIFO queue of callbacks to execute. While each phase is special in its own way, generally, when the event loop enters a given phase, it will perform any operations specific to that phase, then execute callbacks in that phase's queue until the queue has been exhausted or the maximum number of callbacks has executed. When the queue has been exhausted or the callback limit is reached, the event loop will move to the next phase, and so on.
Since any of these operations may schedule _more _operations and new events processed in the poll phase are queued by the kernel, poll events can be queued while polling events are being processed.
timers : this phase executes callbacks scheduled by
setTimeout()andsetInterval()I/O callbacks: executes almost all callbacks with the exception of close callbacks, the ones scheduled by timers, and
setImmediate()idle, prepare: only used internally.
poll: retrieve new I/O events; node will block here when appropriate.
check:
setImmediate()callbacks are invoked here.- close callbacks: e.g.
socket.on('close', ...)
Phases in Detail
timers
A timer specifies the threshold after which_a provided callback_may be executed_rather than the exact time a person_wants it to be executed. Timers callbacks will run as early as they can be scheduled after the specified amount of time has passed; however, Operating System scheduling or the running of other callbacks may delay them.
I/O callbacks
This phase executes callbacks for some system operations such as types of TCP errors. For example if a TCP socket receives ECONNREFUSEDwhen attempting to connect, some *nix systems want to wait to report the error. This will be queued to execute in the I/O callbacks phase.
poll
The poll phase has two main functions: When the event loop enters the poll phase and there are no timers scheduled, one of two things will happen:
If the poll queue is not empty, the event loop will iterate through its queue of callbacks executing them synchronously until either the queue has been exhausted, or the system-dependent hard limit is reached.
If the poll queue is empty, one of two more things will happen:
If scripts have been scheduled by
setImmediate(), the event loop will end the poll phase and continue to the check phase to execute those scheduled scripts.If scripts have not been scheduled by
setImmediate(), the event loop will wait for callbacks to be added to the queue, then execute them immediately.
Once the poll queue is empty the event loop will check for timers whose time thresholds have been reached. If one or more timers are ready, the event loop will wrap back to the timers phase to execute those timers' callbacks.
check
This phase allows a person to execute callbacks immediately after the poll phase has completed. If the poll phase becomes idle and scripts have been queued with setImmediate(), the event loop may continue to the check phase rather than waiting.
setImmediate()is actually a special timer that runs in a separate phase of the event loop. It uses a libuv API that schedules callbacks to execute after the poll phase has completed.
Generally, as the code is executed, the event loop will eventually hit the poll phase where it will wait for an incoming connection, request, etc. However, if a callback has been scheduled with setImmediate()and the poll phase becomes idle, it will end and continue to the check phase rather than waiting for poll events.
close callbacks
If a socket or handle is closed abruptly (e.g.socket.destroy()), the'close'event will be emitted in this phase. Otherwise it will be emitted via process.nextTick().
process.nextTick()
process.nextTick()is not technically part of the event loop. Instead, the nextTickQueuewill be processed after the current operation completes, regardless of the current phase of the event loop.
Why we use process.nextTick(). There are two main reasons:
Allow users to handle errors, cleanup any then unneeded resources, or perhaps try the request again before the event loop continues.
At times it's necessary to allow a callback to run after the call stack has unwound but before the event loop continues.