A Short Introduction to Node.js Event Loop

Alex Korzhikov
May 21 · 5 min read

Last time we were talking about CLI in Node.js , let’s see how one of the essential parts of the technology works internally. The topic for this article is to overview the Node.js Event Loop concept and see the program examples using the Node.js Event-Driven applications design paradigm.

Image for post
Image for post
Awesome Node.js Event Loop Phases

Event Loop

Event Loop is a program, which allows subscribing to system resource events. It provides a callback stack that can be linked to resources and executed when appropriate descriptors are ready.

The Event Loop abstraction might be already known to JavaScript developers as the concept is widely used in programming applications for browsers. FrontEnd programs are structured in the Event-Driven paradigm, by attaching callbacks to user actions.

Timers

The example with timeouts shows the log order in a simple JavaScript program

Asynchronous operations are passed to the internal Event Loop mechanism and scheduled to be executed at some point later. After given timeouts of 1000 and 2000 milliseconds, the first and second callbacks are added to the call stack on a JavaScript engine. The output in the console will be:

2
1
3

In a synchronous environment, without the Event Loop, the output would follow the syntactic code order:

1
2
3

Node.js

In traditional Web Server-side architecture, each call to I/O operations is blocking the program’s main thread. In Node.js when any I/O event occurs, it schedules a task on the libuv stack to process, and continues to run the Event Loop.

When Node.js starts, a few things happen first:

  • the Event Loop initializes,
  • then the given script is executed with dependent libraries and synchronous calls (API, setTimeout, process.nextTick),
  • callbacks to async operations and timeouts are set,
  • after which Event Loop is waiting for events to happen.

After the execution of an initial script is done, the Event Loop starts processing events. If there is nothing to be processed on the main thread, it is put to sleep, but it wakes up every time a system event happens or an operation completes, or a timer goes off. Finally, everything ends with the process#exit event.

Most operations in the Node.js ecosystem exist in both synchronous and asynchronous ways. Each time an asynchronous operation is executed, the Event Loop schedules a delayed callback.

Native modules using Event Loop are:

  • fs
  • http
  • dns
  • … and many others

The file event.js is planned to be read by the Node.js environment, and the callback is attached to that action.

Phases

Libuv is a cross-platform asynchronous I/O library, which implements Event Loop, Timers, Sockets, File System operations, Signal handling, Child processes, and Threads.

It takes care of polling for I/O and scheduling callbacks to be run based on different sources of events.

The phases provided by libuv are the following

Interestingly enough, the libuv phases look recognizable in original code

  • timers - is a phase where callbacks scheduled by setTimeout() & setInterval() are executed
  • pending callbacks - for almost all built-in functions callbacks, except timers, immediates, close types
  • poll - for connections
  • close - events like socket.on('close')

Timeouts, Immediate, and process.nextTick()

  • setTimeout(), setInterval() functionality is almost similar to a browser
  • setImmediate() - special timers, executed during the poll phase
  • process.nextTick()- schedules a callback to execute inside phases

Phases Event Loop Example

Let’s overview what will happen with the following code example of different asynchronous Node.js API calls

First of all, it will not work! 👋😀

The process.nextTick() is recursively calling itself. It's the fastest execution of asynchronous code outside of Event Loop. To be precise, nextTick() callbacks are invoked after current synchronous call. The output will be infinite next messages in the console. Let's fix it quickly

By running a program node event-loop-fix-next.js we will see something like:

Let’s check why it happens 🕵🏾‍♂️👩‍💻

A short remark before we go to the console output

const fs = require('fs')

require() is a part of the Node.js CommonJS module system. It's invocation is synchronous in a program's flow meaning, as well as other APIs in the current example such as setTimeout(), setImmediate(), fs.readFile(), process.nextTick(). Latter functions, however, schedule callbacks to be executed at some point in the future.

The next message is produced by nextTick() call, which is first, before going to the Event Loop phase. The order of the next two messages can differ:

timeout out
immediate out

or

immediate out
timeout out

both variants are possible.

According to the official The Node.js Event Loop, Timers, and process.nextTick() guide,

the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process

Next goes the fs message regardless of whether the file event.js exists in the file system or not. The callback will be invoked either with the first error argument, if the file cannot be read or with the file data otherwise.

Inside the readFile() callback function body callbacks are attached similarly like before. The next in message is the next one. Again, process.nextTick()is the fastest execution of asynchronous code outside of Event Loop, and it’s called at the end of the current phase. Which by the way, is the poll phase.

In the beginning, we saw a non-deterministic behavior of a program with immediate out and timeout out events. Now, on the contrary, the order is strictly defined. The immediate in event is shown before timeout in according to the Event Loop phases diagram.

I’ve made a short video explaining this example:

Hopefully, the Event Loop looks a bit familiar now!

Thanks!

In this article, we’ve overviewed a few aspects of Node.js Event Loop concept. The Node.jsofficial pages contain even more useful examples and descriptions.

Image for post
Image for post
Join our FullStack JavaScript Developer Bootcamp

The good news!

We start a new online JavaScript Full-Stack Bootcamp to deep dive into Node.js and React.js technologies. It starts this June and we hope to see you there!

Join our FullStack JavaScript Developer Bootcamp

And have a nice coding time!

The Startup

Medium's largest active publication, followed by +718K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store