Concepts, like passing callbacks to functions or writing asynchronous code, are often not so difficult to implement, which makes most JavaScript developers care less about what goes on under the hood. They just don’t care about understanding the complexities that have deeply abstracted from them by the language. As a JavaScript developer, it becomes increasingly important to understand what really happens under the hood and how most of these complexities abstracted from us really work. It helps us make more informed decisions, which can, in turn, boost our code performance drastically. This article focuses on one of the very important but seldom understood concepts or terms in JavaScript. The EVENT LOOP!.  Writing asynchronous code can not be avoided in JavaScript, but why does a code running asynchronously really mean? i.e. The Event Loop Before we can understand how the event loop works, we first have to understand what JavaScript itself is and how it works!

What is JavaScript?

Before we proceed, I’d like us to take a step back to the very basics. What really is JavaScript? We could define JavaScript as; Wait, what’s this? A bookish definition? 🤔 Let’s break it down! The keywords here as regards this article are single-threaded, non-blocking, concurrent, and asynchronous.

Single thread

A thread of execution is the smallest sequence of programmed instruction that can be managed independently by a scheduler. A programming language is single-threaded means it can only perform one task or operation at a single time. This means it would execute an entire process from start to end without the thread being interrupted or stopped. Unlike multi-threaded languages where multiple processes can be run on several threads concurrently without blocking each other. How can JavaScript be single-threaded and non-blocking at the same time? But what does blocking mean?

Non-blocking

There is no one definition of blocking; it just simply means things that are running slowly on the thread. So non-blocking means things that aren’t slow on the thread. But wait, did I say JavaScript runs on a single thread? And I also said it non-blocking, which means task run quickly on the call stack? But how??? How about when we run timers? Loops? Relax! We’d find out in a bit 😉.

Concurrent

Concurrency means that the code is being executed concurrently by more than one thread. Okay, things are getting really weird now, how can JavaScript be single-threaded and be concurrent at the same time? i.e., executing its code with more than one thread?

Asynchronous

Asynchronous programming means that the code runs in an event loop. When there is a blocking operation, the event is started. The blocking code keeps running without blocking the main execution thread. When the blocking code finishes running, it queue’s the result of the blocking operations and pushes them back to the stack. But JavaScript has a single thread? What then executes this blocking code while letting other codes in the thread get executed? Before we proceed, let’s have a recap of the above.

JavaScript is single-threaded JavaScript is non-blocking, i.e. slow processes don’t block its execution JavaScript is concurrent, i.e. it executes its code in more than one thread at the same time JavaScript is asynchronous, i.e., it runs blocking code somewhere else.

But the above doesn’t exactly add up, how can a single-threaded language be non-blocking, concurrent, and asynchronous? Let’s go a bit deeper, let’s go down to the JavaScript runtime engines, V8, perhaps it has some hidden threads we aren’t aware about.

V8 Engine

The V8 engine is a high performance, Open-source web assembly runtime engine for JavaScript written in C++ by Google. Most browsers run JavaScript using the V8 engine, and even the popular node js runtime environment uses it too. In simple English, the V8 is a C++ program, which receives JavaScript code, compiles, and executes it. The V8 does two major things;

Heap memory allocation Call stack execution context

Sadly, our suspicion was wrong. The V8 has just one call stack, think of the call stack as the thread. One thread === one call stack === one execution at a time. Since V8 has just one call stack, how then does JavaScript run concurrently and asynchronously without blocking the main execution thread? Let’s try to find out by writing a simple yet common asynchronous code and analyze it together.

JavaScript runs each code line by line, one after each other(single-threaded). As expected, the first line gets printed in the console here, but why is the last line printed before the timeout code? Why doesn’t the execution process wait for the timeout code(blocking) before going ahead to run the last line? Some other thread seems to have helped us execute that timeout since we are pretty sure a thread can only execute one single task at any point in time. Let’s take a sneak peek into the V8 Source Code for a while. Wait… what??!!! There are no timer functions in V8, no DOM? No events? No AJAX?…. Yeeeeessss!!! Events, DOM, timers, etc. aren’t a part of JavaScript’s core implementation, JavaScript Strictly conforms with the Ecma Scripts specifications and various versions of it are often referred to according to its Ecma Scripts Specifications (ES X).

Execution Workflow

Events, timers, Ajax requests are all provided on the client-side by the browsers and are often referred to as Web API. They are the ones that allow the single-threaded JavaScript to be non-blocking, concurrent, and asynchronous! But how? There are three major sections to the execution workflow of any JavaScript program, the call stack, the web API, and the Task queue.

The Call Stack

A stack is a data structure in which the last element added is always the first to be removed from the stack, you could think of it as a stack of a plate in which only the first plate which was the last added can be removed first. A Call Stack is simply nothing but a stack data structure where tasks or code is being executed accordingly. Let’s consider the below example; When you call the function printSquare() , it is pushed onto the call stack, the printSquare() function calls the square() function. The square() function is pushed onto the stack and also calls the multiply() function. The multiply function is pushed onto the stack. Since the multiply function returns and is the last thing that was pushed to the stack, its get resolved first and is removed from the stack, followed by the square() function and then the printSquare() function.

The Web API

This is where code that isn’t handled by the V8 engine is executed to not “block” the main execution thread. When the Call Stack encounters a web API function, the process is immediately handed over to the Web API, where it is being executed and freeing the Call Stack to perform other operations during its execution. Let’s go back to our setTimeout example above; When we run the code, the first console.log line gets pushed to the stack and we get our output almost immediately, on getting to the timeout, timers are handled by browser and aren’t a part of  V8’s core implementation, it’s get pushed to the Web API instead, freeing the stack so it could perform other operations. While the timeout is still running, the stack goes ahead to the next line of action and runs the last console.log, which explains why we get that outputted before the timer output. Once the timer is completed, something happens. The console.log in then timer magically appears in the call stack again! How?

The Event Loop

Before we discuss the event loop, lets first go through the function of the task queue. Back to our timeout example, once the Web API finishes executing the task, it doesn’t just push it back to the Call Stack automatically. It goes to the Task Queue.  A queue is a data structure that works on the First in First out principle, so as tasks get pushed into the queue, they get out in that same order. Tasks that have been executed by the Web API’s, which are being pushed to the Task Queue, then go back to the Call Stack to get their result printed out. But wait. WHAT THE HECK IS THE EVENT LOOP??? The event loop is a process that waits for the Call Stack to be clear before pushing callbacks from the Task Queue to the Call Stack. Once the Stack is clear, the event loop triggers and checks the Task Queue for available callbacks. If there are any, it pushes it to the Call Stack, waits for the Call Stack to be clear again, and repeats the same process. The above diagram demonstrates the basic workflow between the Event Loop and the Task Queue. Conclusion While this is a very basic introduction, the concept of asynchronous programming in JavaScript gives enough insight to clearly understand what is going on under the hood and how JavaScript is able to run concurrently and asynchronously with just a single thread. JavaScript is always on-demand, and if you are curious to learn, I would advise you to check out this Udemy course.

How does the Event Loop works in JavaScript  - 72How does the Event Loop works in JavaScript  - 14How does the Event Loop works in JavaScript  - 47How does the Event Loop works in JavaScript  - 20How does the Event Loop works in JavaScript  - 95