The Call Stack and Event Loop in Node

An overview of how Node.js handles and responds to asynchronous events.

Scroll down...

Content

Resources

Comments

This lesson dives deep into the guts of Node.js to illustrate how the Node event loop works. By the end of this lesson, you'll understand what makes Node.js asynchronous and why it is referred to as having non-blocking event-driven I/O.

What is a Call Stack?

A call stack is many times referred to as "the stack". It stores data about procedures that are currently running in a given program.

...the main reason for having one (a stack) is to keep track of the point to which each active subroutine should return control when it finishes executing.

A stack is also a data structure that stores items. It is a LIFO data structure in that the last item to be stored (pushed) on the stack is the next or "first" item to be removed (popped) from the stack. Why is this significant?

There are various places for stacks and their counterparts queues. Basically, they are important because they store procedures so that they can be executed in an organized fashion. So how do stacks and queues work in the Node.js event loop?

The Node.js Event Loop

Before we dive into what the Node.js event loop is and how it works, we need to identify the various parts of the whole.

  1. Chrome V8 Engine: Google's open source high-performance JavaScript engine, written in C++.
  2. The C libuv library: libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by Node.js.
  3. The Operating System: system software that manages computer hardware and software resources and provides common services for computer programs. All computer programs, excluding firmware, require an operating system to function.

The Chrome V8 engine is responsible for executing JavaScript code. It can actually be embedded into a C++ application which is what Node.js is at its core. The V8 engine takes in JavaScript as a string, executes it and then prints the result to STDOUT. However, there is an issue with this because JavaScript is synchronous. So how does Node.js allow V8 to execute synchronous JavaScript code while performing asynchronous operations?

The following diagram illustrates the communication between these various pieces of Node's event-driven I/O.

Node.js event loop

The diagram can be broken down into these steps:

  1. V8 runs JavaScript that requires an asynchronous task to be performed
  2. The libuv library submits a request to the OS to perform the task
  3. The task is placed onto a queue of tasks that will complete sometime in the future
  4. The event loop constantly checks to see if any tasks in the queue are complete
  5. Once the event loop finds a completed task it returns it to continue executing the corresponding JavaScript callback

By viewing this diagram and understanding these steps, it is easy to see that the Node.js event loop is exactly that: it is a continuously looping process that is checking to see if other processes have completed. Let's examine the code from the previous lesson again:

var fs = require('fs');
var path = './data/lorem.txt';

fs.readFile(path, 'utf8', function(err, data) {
  console.log('Async!');
  err ? console.error(err) : console.log(data);
});

console.log('Done!');

It should now be more clear how the program logs "Done!" before it logs the contents of the file. The V8 engine continues to execute the JavaScript outside of the callback and when the asynchronous task is complete the Node.js event loop notifies V8 and runs the callback.

Wrapping Up

Having a solid understanding of the Node.js event loop is key to forming a clear mental model of how Node.js works. You now have been given a tour of the various major pieces of Node.js and that which enables it to have event-driven non-blocking I/O.



Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

Sorry, comments aren't active just yet!

Next Lesson: File I/O Basics and Callbacks in Node