Today I attended Will Sentance’s workshop “JavaScript Hard Parts” on Frontend Masters. It was a foundational overview of how asynchronous JavaScript is processed using the JavaScript Event Loop. This is not a perspective that I have studied before. Perhaps I should have. Learning about it helped me to understand how things work at a deeper level across the entire language.

The first building block to understanding asynchronous JavaScript is to identify the core processing components of JavaScript, and understand how they work together using the Event Loop. Below is a brief walk through it.

JavaScript Processing Components

  1. JavaScript Engine
  2. Runtime Environment (usually a web browser or Node.js)
  3. Event Queue
  4. Call Stack

The JavaScript Engine is the component that compiles and executes JavaScript. This may seem obvious, but consider a call to setTimeout. That is not a JavaScript function. setTimeout is an Environment API method. All methods that interact with the DOM are also Environment APIs.

Pure JavaScript, ie: var num = 10;, is processed in the JavaScript Engine. But Environment API methods are processed outside of the JavaScript Engine in the Runtime Environment. If it weren’t for these Environment APIs, JavaScript would be far less useful because it would not be able to interact with the outside world. So, it’s important to understand how the components work together using the JavaScript Event Loop. Let’s look at a simple example.

JavaScript Event Loop

function sayHi() {
    console.log('hi');
}

setTimeout(sayHi, 0);

console.log('hi first');

On line 1, sayHi is declared as a function in the global scope. Memory is allocated in the JavaScript Engine, and the body of the function is stored (lines 1–3). sayHi points to that location in memory. You can verify this in your browser’s console.

Want a better understanding of how declaration, assignment, and execution is processed in JavaScript? Check out my post on Hoisting in JavaScript.

Screenshot of a value referencing a function in Chrome Dev Tools
Function Reference In Memory

On line 5, setTimeout is called. This is where things get interesting. Because setTimeout is an Environment API, it is processed outside of the JavaScript Engine in the Runtime Environment. As you may know, the second parameter of setTimeout accepts a number argument representing a delay. While you could say this delay defines how long it should be until sayHi is executed, more specifically, it defines how long it will be until sayHi is added to the Event Queue by the Runtime Environment.

In our example, sayHi will be added to the Event Queue after 0 milliseconds. It will remain in the Event Queue until the Call Stack is completely empty. The Call Stack will be empty when all functions in all scopes have executed. At that point, the Event Queue will push the first item its queue (sayHi) to the top of the Call Stack. The process of monitoring the Call Stack, then transferring items from the Event Queue to the Call Stack is referred to as the “Event Loop“.

The Event Loop operates on a first-in, first-out order (FIFO for you accountants turned programmers). A mental model of this process can be established with the analogy of taking trip to the store. You leave your home (the JavaScript Engine) for the store (the Runtime Environment). There, you put an item in your shopping cart and head to the checkout line (the Event Queue). Once it is your turn, you move the item from your cart to the top of the checkout counter (the Call Stack) and the transaction is processed. You then head back to your home (the JavaScript Engine) with the item.

Meanwhile, just because you left to run an errand doesn’t mean the activity at your house stops. So, to complete the analogy, while setTimeout is processed in the Runtime Environment, then added to the Event Queue, before being pushed to the Call Stack, console.log('hi first'); is executed. That is why you see hi first logged before hi.

Screenshot containing an asynchronous function execution to illustrate the JavaScript Event Loop
Asynchronous Function Execution

I hope this explanation helps to clarify how the JavaScript Event Loop works. Thanks for taking the walk!

Posted by: John Dugan

Comments