Asynchronous JavaScript (JS) Demystified
Tags: javascript, generalconcepts
Published: 2021-12-15 20:22:12

---
title: Asynchronous JavaScript (JS) Demystified
published: true
date: 2021-12-15 11:13:13 UTC
tags: JavaScript,GeneralConcepts
series: JavaScript
canonical_url: https://www.underthehoodlearning.com/asynchronous-javascript-demystified
cover_image: https://res-5.cloudinary.com/under-the-hood-learning/image/upload/q_auto/v1/blog_images/async-js-timer.gif
---

In this article, we will look under the hood to understand how asynchronous function is executed in JavaScript. We will explore concepts such as **call stack, event loop,** and **message queue** which are the key players behind asynchronous JS.

JavaScript is a single-threaded programming language - _a language with one single **call stack** and a single **memory heap.** _ What it means is that the **JavaScript engine** can only process one statement at a time in a single thread.

Although single-threaded languages offer some levels of simplicity since developers don't have to worry about concurrency, applications coded in single-threaded programming languages face challenges with long operations (such as network access) blocking the main thread. For example, imagine what it feels like when the web page is unresponsive even just for a few seconds after you clicked a button to request some data from the API. It would be annoying, would it?😉

That's where **asynchronous JavaScript** comes into play. Using asynchronous JavaScript **(callbacks, promises, async/await),** we can perform long network requests without blocking the main thread. But **how?** 🤔

Before we dive into **asynchronous JS,** let's first try to understand how its counterpart, **synchronous code,** gets executed inside the JS engine by looking at some simple codes.

## How is synchronous code executed by the JS engine?
<!--kg-card-begin: markdown-->
```
const second = () => {
  console.log('Hello there!');
}
const first = () => {
  console.log('Hi there!');
  second();
  console.log('The End');
}
first();

```
<!--kg-card-end: markdown-->

When the above code executes, the following outputs are logged in the console:

<!--kg-card-begin: markdown-->
```
Hi there!
Hello there!
The End

```
<!--kg-card-end: markdown-->

To understand how the above code executes inside the JS engine, we have to understand the concept of **_execution context_** and the **_call stack_**.

### Execution Context

An **execution context** is an abstract concept of an **_environment_** where the JS code is evaluated and executed. Whenever any code is run in JS, it's run inside an execution context.

By _ **environment,** _ we mean the value of `this`, `variables`, `objects`, and `functions` JS code has access to at a particular time.

There are three types of execution context in JS:

- **Global execution context:**  
This is the default execution context in which JS code starts its execution when the file first loads in the browser. All global code, _i.e. code that is not inside any function or object,_ is executed inside the global execution context. 
- **Functional execution context:**  
This is the execution context created by the JS engine whenever it finds a function call. Each function has its own execution context. Functional execution context has access to all the code of the global execution context but not vice versa.
- **Eval:**  
Execution context inside `eval` function.

### Call Stack

The call stack is a stack with a **Last In First Out (LIFO)** structure, which is used to store all the execution context created during code execution. The LIFO structure implies that the items can be added or removed from the top of the stack only. Let's use the example code above to illustrate what this really means.

![Asynchronous JavaScript (JS) Demystified](https://res-4.cloudinary.com/under-the-hood-learning/image/upload/q_auto/v1/blog_images/Async-JS.png)

1. When the code is executed, a global execution context is created represented by the `main()` method and pushed to the top of the call stack.
2. When a call to `first()` is encountered, it's pushed to the top of the stack.
3. Since `console.log('Hi there!')` is called from within the `first()` method, it's pushed to the top of the stack, and the "Hi there!" message is logged to the console. Once finished, it's popped off the stack. 
4. Next, we call `second()`, so the `second()` function is pushed to the top of the stack.
5. Since `second()` calls `console.log('Hello there!')`, it's pushed to the top of the stack, and the "Hello there!" message is logged to the console. Once finished, it's popped off the stack followed by the `second()` function.
6. The last thing that remains in the `first()` function is the call to `console.log('The End')`, so it's pushed to the top of the stack, and the "The End" message is logged to the console. Once finished, it's popped off the stack.
7. Since there is nothing left inside the `first()` function, it's popped off the stack followed by `main()`.

## How is asynchronous code executed by the JS engine?

Now that we know how synchronous code executes, let's look at how **asynchronous code** executes.

As mentioned above, network requests take time. Depending upon the situation, the server might take some time to process the request while blocking the main thread making the web page unresponsive. The solution to this problem is to use **asynchronous callbacks** to make out code non-blocking. An example of an asynchronous callback function is shown below. Here, we used the `setTimeout` method (available from the **Web API** in browsers) to simulate a network request.

<!--kg-card-begin: markdown-->
```
const networkRequest = () => {
  setTimeout(() => {
    console.log('Async Code');
  }, 2000);
};

console.log('Hello World');
networkRequest();
console.log('The End');

```
<!--kg-card-end: markdown-->

When the above code executes, the following messages are logged to the console:

<!--kg-card-begin: markdown-->
```
Hello World
The End
Async Code

```
<!--kg-card-end: markdown-->

So, it seems that the call to `networkRequest()` did not block our thread after all. But we said earlier, that JavaScript is a single-threaded language, so is that even possible?🤔 To understand how this code is executed, we need to understand a few more concepts such as **event loop** and **message/task queue.**

JavaScript has a concurrency model based on **event loop,** which is responsible for _executing the code, collecting and processing events, and executing queue sub-tasks._

### Message Queue

A JavaScript runtime uses a **message queue,** which is a list of messages to be processed. Each message has an associated _ **function** _ that gets called in order to handle the message.

At some point during the **event loop** when the call stack is empty **,** the runtime starts handling the messages on the queue, starting with the oldest one. The message is removed from the queue and its corresponding function is called. This process repeats every time the **event loop** detects that the call stack is empty indicating the next message in the queue (if available) can be processed.

**ES6** introduced the concept of **job queue/micro-task queue,** which is used by **Promises** in JS. The difference between the message queue and the job queue is that **_the job queue has a higher priority than the message queue,_** which means that promise jobs inside the job queue/micro-task queue will be executed before the callbacks inside the message queue.

### Event Loop 

The **event loop** got its name because of how it's usually implemented, which usually resembles:

<!--kg-card-begin: markdown-->
```
while (queue.waitForMessage()) {
  queue.processNextMessage()
}

```
<!--kg-card-end: markdown-->

The job of the event loop is to look into the call stack and determine if the call stack is empty or not. If it's empty, it looks into the **message queue** to see if there's any pending callback waiting to be executed. Each message is processed completely before another message is processed.

In web browsers, messages are added anytime an event occurs and there is an event listener attached to it.

> The **event loop, message queue,** and **web APIs** are not part of the JS engine. They are part of the browser's JS runtime environment **Node.js** runtime environment in the case of Nodejs.

With all of that out of the way, let's revisit our example of asynchronous callback and dissect it.

<!--kg-card-begin: markdown-->
1. When the above code loads in the browser, the `console.log('Hello World')` is pushed to the stack, and the "Hello World" message is logged to the console. Once finished, it's popped off the stack.  
 ![Asynchronous JavaScript (JS) Demystified](https://res-1.cloudinary.com/under-the-hood-learning/image/upload/q_auto/v1/blog_images/1.png)
2. Next, the `networkRequest()` is called, so it's pushed to the top of the stack.  
Since `setTimeout()` is called from within `networkRequest()`, it's pushed to the top of the stack. This method takes two arguments: a time in `ms` and a callback function that is to be executed once the timer expires. The `setTimeout()` method starts a timer of 2s in the web API environment.  
 ![Asynchronous JavaScript (JS) Demystified](https://res-2.cloudinary.com/under-the-hood-learning/image/upload/q_auto/v1/blog_images/2.png)
3. At this point, the `setTimeout()` has finished and is popped off the stack.  
Next, the `console.log('The End')` is pushed to the stack, and the "The End" message is logged to the console, after which the function is popped off the stack.  
 ![Asynchronous JavaScript (JS) Demystified](https://res-5.cloudinary.com/under-the-hood-learning/image/upload/q_auto/v1/blog_images/3.png)
4. Meanwhile, the timer has expired, and the callback is pushed to the message queue. At this point, since the call stack is empty, the event loop pushes the callback in the queue to the top of the call stack. Since the callback calls `console.log('Async Code')`, it's pushed to the top of the stack. The "Async Code" message is logged to the console before it's popped off the stack.  
 ![Asynchronous JavaScript (JS) Demystified](https://res-5.cloudinary.com/under-the-hood-learning/image/upload/q_auto/v1/blog_images/4.png)
5. Since the callback is finished, it's also popped off the stack and the program finally finishes.
<!--kg-card-end: markdown-->

That's it. I hope that by now, asynchronous function call in JS is no longer a mystery to you.😉