How Does JavaScript Work?🧐

How Does JavaScript Work?🧐

Ever wondered how JavaScript works behind the web? Or still can't grasp the concept? Well, I'll be happy to make it crystal clear for you :)

·

7 min read

There is nothing more exciting than learning to code for the first time. We get so passionate that we want to start building projects right away. However, we tend to miss the one thing that can bring more meaning in the way we write codes which is... the fundamentals.

Let's get started, shall we? Feel free to grab your cup of coffee:)

First of all, what is JavaScript?

JS is a single-threaded language that can be non-blocking. 'Hmm okay..what does that mean?' Well, being single-threaded means that it can only run one set of instructions at a time. Think of it as reading a food recipe, you have to follow instructions one by one from top to bottom right? It's not doing multiple things, and that's because it has only one Call Stack.

Call Stack

Call Stack & Memory Heap

  • A Call Stack is what let JavaScript Engine keep track of function calls but, most importantly it is what allows us to run code one at a time. In short, when you call a function, the interpreter will add it to the call stack first then start carrying out the function and once it has been run, it will be removed from the call stack.
  • To call functions, they have to be stored somewhere..and that somewhere is in the Memory Heap. It's a form of resource management applied to computer memory. It is used to provide ways to dynamically allocate portions of memory to programs at their request, and free it for reuse when no longer needed.

Stack and Memory Heap

Memory Leak

That's what happens when a computer program incorrectly manages memory allocations and this is when the memory is not released when it's no longer needed.

The good news, this issue was fixed when JS Engine introduced the Garbage Collector.

Garbage Collector (GC)

Garbage Collection is a form of automatic memory management. It will attempt to reclaim memory which was issued by the program but is no longer needed.

Stack Overflow

You might have ever heard of it? Well, since we know that there is one call stack that means we are also quite limited. A stack overflow happens when the call stack space is exceeded.

But how?

The most common cause is infinite recursion, where a function calls itself so many times that the space needed to store the variables and information connected with each call is way more than we can fit on the stack.

Perhaps an example might help :)

function hello() {
    console.log("Helloo, you are awesome!!!");
    hello();
}
hello();

And here, we just created an infinite loop that will run indefinitely. If we try to run it inside the browser, the function will run until the stack space is exceeded as you can see in the picture shown below 👇. Stack Overflow

Are you still following? Great, let's continue!

Now that we know what JavaScript is, we need to know how it works.

The JavaScript Engine

As you might know, computers only understand binary codes which are 0s and 1s, meaning that they can't simply execute our JavaScript files since they can't understand what's written inside. That's where the JS Engine plays its most important role.

JavaScript engine process

Instead of sending our JS file straight to the CPU, we first of all need, a translator to make the computer understand what we want it to do. As in the picture shown above, the engine takes our file, executes the compilation to binary instructions then sends it to the CPU to finally run it.

Did you know?

The first JavaScript Engine was created in 1995 by Brendan Eich. Before that, browsers were barely interactive since they were only run in HTML & CSS.

Inside the JavaScript Engine

Inside the Javascript engine

When we run a JS file, first it goes through the Parser which will perform a lexical analysis, which means it will break the code into tokens to identify their meaning or to know what the code is trying to do.

Secondly, the tokens will get formed into an Abstract Syntax Tree (AST). An AST is a tree representation of the source code of a computer program.

Now, before continuing I'd like to talk about two important things in a JS Engine that quite often confuse people, and that is..an interpreter vs a compiler.

Interpreter Vs Compiler

In programming, there are generally two ways of translating to machine language, let's start with the first one.

  • An interpreter, what it does is read and translate the files line by line. This can be a slow process however, the program runs right away and you will be able to catch any error on the spot.

  • With a compiler, unlike an interpreter, it doesn't start to translate immediately. What it does is, it works ahead of time to create a translation. In short, instead of having to wait for the program to run instructions one at a time, a compiler will simply read the whole file at once and then execute. Yes, it does take some preparation time since the compiler needs to first read all the instructions but then after that, it will run very quickly.

Did you know?

JavaScript originally came as an interpreted language but now we can use a compiler to optimize the code.

Difference between an interpreter and a compiler

Now you might be wondering which one to use between a compiler and an interpreter but guess what, there is the best of both worlds! Google came up with the V8 Engine using both interpreter and compiler also known as JIT (Just In Time) compiler to make the engine runs faster.

Perfect! Now that we know what JavaScript is and how it works, there is still one small issue. If JavaScript has one call stack and runs one instruction at a time, wouldn't it take an eternity to run a large program? Well, yes but this is where the JavaScript Runtime comes in!

What's a JavaScript Runtime?

Runtime is an environment in which a programming language executes. This will make the browser keep working in the background while the synchronous javascript code is running, this uses the Web API to communicate.

Keep in mind 💭

It's good to be mindful that the runtime environment can have different forms based on the context. For example, a browser runtime environment can be very different from a Node.JS. However, these differences are mostly on the implementation level, meaning that the following concepts are still relevant.

JavaScript Runtime

Web API

First of all, what's an API?

An API is an Application Programming Interface. In short, it's a kind of interface that has a set of functions that allow programmers to build software/applications or get access to some specific features or data of an application.

Now, a Web API which is not part of the JS engine but is instead provided by the browser, will simply extend the browser functionality by doing multiple tasks such as sending HTTP requests, listening to DOM events, delaying executions using a callback, etc...

These Web APIs are called Asynchronous. Why? Because they can run instructions in a different order compared to JS which can only run from top to bottom.

How does it work?

Using setTimeout, you can delay the first instruction to be able to run the second instruction first.

Let's take a look :

console.log("First");

setTimeout(() => {
    console.log("Second");
}, 1000 );

console.log("Third");
/*
OutPut: First,
        Third,
        Second
*/

As you can see in the example shown above, console.log("Second") was written second but came as last in the output.

But how?

  1. Alright, so what happened here is, we ran the console.log("First") and then set a delay on the console.log("Second") for 1-second.
  2. Since setTimeout is a function from the Web API, the call stack cannot understand it so it will send the function to the web API to handle it. (By the time it sent the setTimeout function, it will proceed with the console.log("Third"))
  3. Finally, the Web API will read the setTimeout function then wait for the 1-second delay that was defined by us, goes through the Callback Queue then finally back to the call stack.

Callback Queue

The Callback queue is a data structure that uses the FIFO (first-in-first-out) principle. That's where all the asynchronous callback functions need to go first before being sent to the call stack, it will simply try to maintain the order in which the message or method was added to the queue.

Event Loop

The event loop will keep checking consistently if the call stack is empty and if there is any message left in the event queue. Its purpose is to move the message from the callback queue to the call stack but only when the call stack is empty.

Event Loop

Hope you enjoyed this article ❤️

Alriight, that was quite a lot of new information, congrats to you if you made it so far! Feel free to bookmark this if you'd like to come back at it in the future.

Let me know if you enjoyed it by leaving a like or a comment :) or if there is a topic that you'd like me to write about.

Thanks for your time,

Happy coding :)