How JavaScript Works?
Tags: javascript, webdev, programming, beginners
Published: 2022-07-24 11:29:00

**In this article we are going to take a look at the computer science behind Javascript.**

> **NOTE**: _Keep in mind that you do not need to understand these concepts to begin using JavaScript productively. Years of development experience may be required before they truly sink in._

We learnt in the [last article](https://dev.to/iarchitsharma/the-history-of-javascript-5e98) that Javascript is a programming language based on the ECMA 262 Spec, but to study how it works in a computer system, we must travel to the absolute bottom of the stack, which is the bare metal CPU and Memory on a machine.
![Level of Abstraction](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19dnibvpa9ddcqtr239n.png)
 
When you run a _JavaScript programme_, whether it's a web application in the browser or something server side with **nodejs**, it needs to _allocate memory on your RAM_ to store things for the runtime and variables and objects that you reference in your code, and it also needs a _thread from your CPU to actually execute the instructions in your code_, but here's the thing: as a JavaScript developer, you never really have to think about this stuff because it's a **high-level language**.

> **High-Level:** _refers to the abstraction the language provides over the machine’s bare-metal hardware. JavaScript is considered high-level because it does not require direct interaction with the operating system, hardware. In addition, it does not require memory-management like C/C++ because the runtime always uses garbage-collection._

But what exactly do we mean by _high-level_? We're referring to the degree of abstraction or simplification that the language provides over the computer's hardware. **Machine code** is the lowest level language; it is a numeric language that can be executed directly by the CPU; however, it would be extremely difficult to build a website with it because you would have to memorize a number for each and every instruction that you want to run.

Moving up one level to **Assembly** provides some syntactic sugar, but each assembly language is specific to a specific CPU or operating system
So we can move up another level to the **C language**, which provides a modern syntax and the ability to write cross-platform programmes, but developers must still be concerned with _low-level issues_ such as memory allocation.

Another step up brings us to languages like **JavaScript** and **Python**, which use _abstractions_ like _garbage collectors and dynamic typing_ to simplify the way developers write their applications.
![Working of Interpreter and Compiler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iigr8id3i42fz8noqum4.png)
 
There are two basic techniques to convert programming language code into something that the CPU can actually execute, so let's go ahead and define a few crucial terminology related to JavaScript.
One of them is called an **Interpreter**, and the other is called a **Compiler**.

> **Interpreted or Just-in-Time Compiled:** _Interpreted means the source code is converted to bytecode and executed at runtime (as opposed to being compiled to a machine code binary at build time). This is also why JS is commonly called a “scripting language”. Originally, it was only interpreted, but modern JS engines like V8, Spidermonkey, and Nitro use various techniques to perform Just-in-Time Compilation or JIT for better performance. Developers still use JS like an interpreted language, while the engine magically compiles parts of source code to low-level machine code behind the scenes._

_JavaScript is an interpreted language_, which means that it requires an environment to read the actual source code and be executed. We can show this by simply opening the browser and running some JavaScript code from the console.
This is different from _compiled languages_ like **Java** or **C**, which will statically analyse all of your code beforehand and then compile it into a binary that you can actually run on the computer.

JavaScript is a dynamically typed language, which tends to be a common characteristic with high-level interpreted languages.
We can examine this by comparing some statically typed Java code to some dynamically typed JavaScript code.

> **Dynamic Weakly Typed:** _Dynamic most often refers to the type system. JS is dynamic weakly typed language, meaning you do not annotate variables with types (string, int, etc) and the true types are not known until runtime._

![Static vs. Dynamic typed languages](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/icdljfh72d8mhv63nyc2.png)

When comparing, you'll notice that the **Java** code annotates things like _integers and strings_, but the **JavaScript** types are unknown or implicit. This is because the type is associated with a _runtime value_ rather than the _actual variables or functions_ in your code.

You may also hear that JavaScript is a **Multi-Paradigm** language at this point. _Most general-purpose programming languages support multiple paradigms, allowing you to combine declarative functional techniques and imperative object-oriented approaches_.

> **Multi-Paradigm:** _means the language is general-purpose or flexible. JS can be used for declarative (functional) or imperative (object-oriented) programming styles._

 ![Prototypal Inheritance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z21fj2osxgtwopm4hz0d.png)
 
**Prototypal inheritance** is the foundation of JavaScript. Everything in JavaScript is considered to be an object, and each object in the language has a link to its prototype, forming a prototype chain from which subsequent objects can inherit their behaviours. If you're used to class-based inheritance, this could seem strange to you, but it's one of the low-level ideas that makes JavaScript a very flexible multi-paradigm language.

> **Prototypal Inheritance:** _means that objects can inherit behaviors from other objects. This differs from classical inheritance where you define a `class` or blueprint for each object and instantiate it. We will take a deep dive into prototypal inheritance later in this course._

######Here is an Example:
```
let animal = {
  eats: true
};
let rabbit = {
  jumps: true
};

rabbit.__proto__ = animal; // (*)

// we can find both properties in rabbit now:
alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true
```
Javascript is a _High-level Interpreted, Dynamically Typed, Multi-Paradigm Prototype Language_, but it is also a _Single Threaded, Garbage Collected, Non-Blocking language with an Event Loop that can be compiled Just-In-Time_.
The first set of definitions is largely relevant to how javascript is laid out in **ECMA 262** - however it doesn't describe how memory should be managed and it doesn't even mention the event loop in the entire 800 page document, so it's up to _browser vendors to handle these implementation_ details.
![JIT Compilatio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5z5orx0ztvxq7sgjvefc.png)
 
**Spider monkey from Mozilla** and **v8 from Google** are two of the most popular implementations. Their methods differ slightly, but they both use a technique known as **Just-In-Time Compilation**.

In the case of v8, it will compile all of your JavaScript down to _native machine code_ before running it, rather than _interpreting bytecode line by line_ as a normal interpreter would.

So, while these JavaScript engines do not fundamentally change the way developers write code, the **JIT compiler** improves performance in browsers and on **Node**.

Because JavaScript is a single-threaded language, it can only do one computation at a time.
######Try this : Open the console with `Ctrl+Shift+J` in this browser tab and then build a while loop that never stops.

```
while(true){}
```
If you try to click on something in this browser tab, it will never catch the event since the single thread is locked in that while loop and can't move on to the next event.

![Task Manager ss](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y2d9rz4fahswsbv0y9oe.jpg)
Enter _Chrome Task Manager_ and you should see the browser tab using nearly 100% of the CPU cores resources. Go ahead and _end the process and refresh the tab_.

When you run your JavaScript code, the _machine allocates two regions of memory_: the call **Stack** and the **Heap**.

The **call Stack** is intended to be a high-performance continuous memory region used to execute your functions. When you call a function, it generates a frame and a call stack with a copy of its local variables. When you call a function within a function, it adds another frame to the stack, but when you return from a function, it removes that frame from the stack.

I believe that going through some of your own code frame by frame is the best approach to grasp the call stack.
######Here is a video for that:
{% embed https://youtu.be/W8AeMrVtFLY %}

When we encounter something a little more complex, such as an object that may be referenced by several function calls outside of this local context, the **Heap** comes into play.

The **Heap** is **Garbage Collected**, which means that V8 or the JS runtime will try to clear up free memory when it's no longer referenced in your code. This doesn't mean you shouldn't be concerned about memory, but it does mean you don't need to manually allocate and free up memory as you would in **C**.
![Event Loop Stack heap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpuon2pszohx283cp22k.gif)
 
We've already seen how a simple while loop can completely break a single-threaded language, _so how can we handle any kind of long-running task_? The answer is the **Event Loop**.

> **Event-Loop Concurrency Model:** _Event Loop refers to a feature implemented by engines like V8 that allow JS to offload tasks to separate threads. Browser and Node APIs execute long-running tasks separately from the the main JS thread, then enqueue a callback function (which you define) to run on the main thread when the task is complete. This is why JS is called non-blocking because it should only ever wait for synchronous code from your JS functions. Think of the Event Loop as message queue between the single JS thread and the OS._

Let's start from scratch and write our own code. In its most basic form, it's just a while loop that waits for messages from a queue and then processes their synchronous instructions until completion.
```
while (queue.waitForMessage()) {
  queue.processNextMessage();
}
```
In the browser, you're already doing this without even thinking about it; you might set up an **Event Listener** for a button click, and when the user clicks it, it sends a message to the queue, and the runtime will process whatever JavaScript you defined as the callback for that event; this is what makes JavaScript **Non-Blocking**.

Because the only thing it ever does is listen to events and handle callbacks, it's never actually waiting for a function's return value; instead, it's waiting for the CPU to process your _synchronous code_, which is usually on a scale of microseconds.

Consider the first iteration of the event loop. It will first handle all of the synchronous code in the script, and then it will check if there are any messages or callbacks in the queue ready to be processed. We can easily demonstrate this behaviour by adding a set timeout to the top of the script for 0 seconds.
######Here is an example that demonstrates this concept (setTimeout does not run immediately after its timer expires):
```
const seconds = new Date().getSeconds();

setTimeout(function() {
  // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  console.log(`Ran after ${new Date().getSeconds() - seconds} seconds`);
}, 500)

while (true) {
  if (new Date().getSeconds() - seconds >= 2) {
    console.log("Good, looped for 2 seconds")
    break;
  }
}
```
Now you might think that, this timeout should be executed first because it is at the start of the file and has a timeout of 0 seconds, but the event loop won't get to it until the first iteration of synchronous code is completed.

What makes this unique is that you can offload long-running jobs to completely separate thread pools in the browser. For example, you might make an _HTTP call_ that takes a few seconds to resolve or interact with the file system on **Node JS**, but you can do so _without blocking the main JavaScript thread_.
![Micro Task queue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hcqpz942ipd6i9byjivt.jpg)
 
With the introduction of **Promises** and the **Micro Task Queue**, JavaScript had to go and make things a little more strange.
If we include a **Promise** resolve after the **setTimeout()** in our script,
```
setTimeout(() => console.log('Do this first?'),0)
Promise.resolve().then(n => console.log('Do this Second?'))
```
You'd think we have two asynchronous operations with zero delay here, so the set timeout would fire first and the promise second, but there's something called the **Micro Task Queue** for Promises which has priority over the main task queue used for Dom APIs and set timeouts, etc. This means that the handler for the Promise will be called back first. In this case, as the Event Loop iterates, it will first handle the synchronous code, then it will go to the **Micro Task Queue** and handle any callbacks that are ready from your promises.

It will finish by running the callbacks that are ready from your set timeouts or Dom APIs.

#####So this is how JavaScript works, If all of this seems overwhelming, don't worry because you don't need to know any of it to start building things with JavaScript.

######Thank you for reading this article; do follow me for more.