Let me understand how JavaScript works under the hood
Tags: javascript, webdev, programming
Published: 2022-09-28 12:38:46

Did you ever wonder what's going on behind the scenes when you run a very small piece of code in JavaScript? I actually didn't for a long time. 

I wanna understand it with you right now. Let's try to discover together! Hop on the bus, starting! 🚎

I offer to write a very very small code block and try to understand its story:


``` javascript
const totalApples = 10;
const totalBananas = 5;

function getTotalFruits() {
   return totalApples + totalBananas;
}

const totalFruits = getTotalFruits();
```

Cool, we all know that result is 15 here. So easy. But what happened under the hood? 

Before we start, keep in mind that JavaScript is **single threaded** and **synchronous language**:

- It can only execute one thing at a time.
- It executes them line by line from top to bottom.


_FIRST OF ALL,_ **Global Execution Context** is created by **JavaScript Engine**.

---

### JavaScript Engine
Javascript Engine is a program that executes the javascript code.

## Execution Context
_Imagine that_: Execution context is a two-sided place where JS code is declared and executed. Imagine a board which has two sides. 

On the right side (**Memory**), all variables and functions are declared.

On the left side (**Thread of Execution**), code is executed line by line.

There are 2 types of Execution Context:

### Global Execution Context (GEC)
Whenever JS Engine executes a script, it creates a global execution context which all global code handled.

### Function Execution Context (FEC)
Whenever a function is called, it creates a function execution context which has its own local memory and thread of execution.

## LET'S TRY TO VISUALIZE:

Remember our code:

``` javascript
// Step 1
const totalApples = 10;
const totalBananas = 5;

// Step 2
function getTotalFruits() {
   return totalApples + totalBananas;
}

// Step 3
const totalFruits = getTotalFruits();
```

Script executed, and Global Execution Context created:

#### Step 1:
Declare totalApples and totalBananas variables in the memory.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1d7fq2oy34o3vslkjca8.png)

#### Step 2:
Declare getTotalFruits function in the memory.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fp7fp9f2lz0ndmh0q1up.png)

Did you realized you can also save a function in the memory? Let's go on.

#### Step 3 (Part 1):
Declare totalFruits variable in the memory. But do I know value of this variable? NO! We cannot save commands in the memory. So it will be saved as uninitialized at the moment. See it:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ar9zavrc9j75rl7okx8.png)

#### Step 3 (Part 2):
Time to execute our function on Thread of Execution. AND FOR THE FIRST TIME HERE, Function Execution Context comes into our live. Here it is:



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om0zr54wudclol8xddiz.png)

Is that all? NO my friend! Something is missing here. A new term reveals in this step. Whenever you call a function, it pops in **Call Stack**.

### Call stack

Call Stack is where the JavaScript Engine keeps track of where your code is in the execution.
You can basically see which functions is running right now in the Call Stack. 

> 🎤  Imagine that you are a singer. Announcer is calling your name. You are coming and singing your song. When the song is over, you are getting off the stage. Stage is Call Stack here.  🎤

When a function is called, it pops in Call Stack. And it pops out when it has done its job.

Global Execution is running at the bottom as default in Call Stack.

###### _Function called:_


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9le6fx24ypm8o5yjxd1b.png)

###### _Function finished its job:_


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bg4z4c3q0549hyxbrq7d.png)

**Note that:** There is ONLY ONE Call Stack since JavaScript is a single threaded language.

---

HUH! I guess it is done, right? Please warn me, if I do anything wrong. Let's keep up the work. 

#### It looks okay like this, but, what if we add some complexity to our function?

Let's not be afraid and do it!

---

It looks very clean when it goes synchronously. But what will happen when some functions are asynchronous? 

We can basically do it with **setTimeout:**

``` javascript
const totalApples = 10;
const totalBananas = 5;

function getTotalFruits() {
   return totalApples + totalBananas;
}

function runTimer() {
   console.log('timeout run!')
}

const totalFruits = getTotalFruits();

setTimeout(runTimer, 0);

console.log(totalFruits);
```

So guys, here is interesting. New terms reveal here again. 
Did you know that JavaScript doesn't have a timer? Also console? 

Everybody sometimes needs a support, so does Javascript. **WEB APIs** help JavaScript here.

### Web APIs
Web APIs are generally used with JavaScript and add some power to our functionality. Timer, Console, Network requests and many other things are Web APIs' skills, not Javascript. 
JavaScript just communicates with browser via some labels like setTimeout.

## Let's Visualize
Assume that, it is setTimeout's turn in the Thread of Execution and let's try to visualize this step:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blc1wfjgt5sc1e07iui5.png)

hmm, weird things are happening. Let me try to summarize it.
**_Please some attention now:_**

Functions and variables saved in memory as usual. They are executed in the thread. And when it is setTimeout's turn, JavaScript didn't send setTimeout's callback (runTimer) into Call Stack. Instead, it communicated with Web Browser and sent a message like:

''Hey buddy 👋 Can you start a timer for me? And when timer is completed, here is your callback to run (runTimer).''

> As you see, after 0ms, timer is completed, callback is ready to run **BUT** guys, Thread of Execution never stops, exactly like life.

In the time when Web Browser handles timer, functions kept executing in the thread and even if callback(runTimer) is ready to be executed, Call Stack is not empty anymore! And remember: There can be only one execution at a time. BUT I HAVE TWO FUNCTIONS TO RUN IN MY HANDS. 

> What is gonna happen? Is JavaScript broken?!?!!? 
> Please no, we need it.

> Or will JavaScript run my functions in a random order?
> That would be very unpredictable and disaster. 

There should be a better solution.

### 🚨 NEW TERM ALERT 🚨

Our callback is waiting in **Callback Queue**.

### Callback Queue
Callback Queue is kind of a waiting room for callbacks which are ready to be executed. Callback is waiting here for the Call Stack to empty. Whenever is Call Stack is empty, our callback pops in Call Stack and do its job.

### Event Loop
Event Loops basically checks Call Stack continuously, and when Call Stack is empty, let there know about it. And first callback in the queue pops in Call Stack.

## Let's add some visuals including Callback Queue and Event Loop


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thv1lmh3tp5869c25oyr.png)

Oh guys, victory! 🏆

**Just a little question;** What if current execution continues for 1000 seconds or whatever while our callback is waiting in Callback Queue? Is it gonna wait forever? 

Sounds unbelievable but yes! Whatever the cost, it is gonna wait until Call Stack is empty. No permission to run unless Call Stack is empty.

Okay! Adventure of this code block completed here, right? But I feel like we can add some more complexity here. 

---

PLEASE DON'T LEAVE ME! I PROMISE THIS IS LAST SECTION. You will not regret, be patient!

---

What would happen if I need to fetch data from server?

### Let's fetch some data:

``` javascript
const totalApples = 10;
const totalBananas = 5;

function getTotalFruits() {
   return totalApples + totalBananas;
}

function runTimer() {
   console.log('timeout run!')
}

function showData(data) {
   console.log(data)
}

const totalFruits = getTotalFruits();

setTimeout(runTimer, 0);

// Fetch some data
const fetchData = fetch('https://jsonplaceholder.typicode.com/todos/1');

fetchData.then(showData);

console.log(totalFruits);
```

Okay, when we fetch data, we will communicate with Web Browser again. Because we need its APIs here.

I will not mention about details of fetch API, just talk about what is going on in the Thread of Execution, Call Stack and Queue while fetching data.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/je8w6c4vu3wtzkw47p3m.png)

Hmm, let's try to write down a timesheet about what happened here:

**1)** Functions and variables saved in the memory, executed in the thread blablabla...

**2)** setTimeout communicated with Web Browser's timer.

**3)** setTimeout's callback (runTimer) is ready and waiting in Callback Queue after 0ms. _[0ms]_

**4)** fetch is doing two jobs:
 **_a)_** Communicated with Web Browser's network feature.
 **_b)_** Created a special Promise Object in the memory via Javascript Engine.

**5)** fetch's callback (showData) is ready with data to run after 200ms **BUT** we don't know yet where it is waiting right now. We'll see. _[200ms]_

**6)** While all those are happening, console.log(15) popped in Call Stack. **AND assume that:** it has taken 250ms to console and after 250ms it will pop out from Call Stack. _(I know it wouldn't take that time in real life but just an assumption to understand the story)_. _[250ms]_

**_So_**, console.log(15) is running in the Call Stack, runTimer is waiting in Callback Queue. Where is _showData_ waiting?

Based on our current knowledge, _showData_ should be waiting right behind _runTimer_ in the Callback Queue, right?

No my friend, it is not. 
For the last time,🚨**New Term Alert**🚨:

There is an another kind of queue here besides Callback Queue.

### Microtask Queue
Whenever a callback is related to Promise Object in JavaScript Engine, it will be waiting in Microtask Queue such as callbacks of fetch functions.

**Note that:** Microtask Queue has a privilege over Callback Queue. 

First, callbacks in Microtask Queue will pop in Call Stack. After they are done, callbacks in Callback Queue will start to pop in Call Stack.

In our scenario, firstly, _showData_ will run because it is waiting in Microtask Queue. And then, _runTimer_ which is waiting in Callback Queue will run.

## Then, final result looks like:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aby16b71k8hfeltizy0d.png)

---

What an adventure! 😓 just a fucking piece of code, crazy.
Our journey ends here, guys. 🚎 thank you for joining me!

Stay in touch with me for more adventures 👇

---

## Follow me on:

**Github:** https://github.com/inancakduvan/
**Twitter:** https://twitter.com/InancAkduvan

###

Thank you for coming with me until end of the reading! 🙂