In this article, we will discuss the internal working of JavaScript in the run-time environment and the browser. This will be an overview walk-through of all the core components that are involved in the execution of JavaScript code.
Before starting let me tell revisited you, What is JavaScript? or the proper definition of JavaScript?
JavaScript is a HIGH-LEVEL, PROTOTYPE-BASED OBJECT-ORIENTED, MULTI-PARADIGM, INTERPRETED or JUST-IN-TIME COMPILED, DYNAMIC, SINGLE-THREADED, GARBAGE-COLLECTED programming language with FIRST-CLASS FUNCTIONS and a non-blocking EVENT LOOP CONCURRENCY MODEL.
let me explain to you-
- HIGH LEVEL:- Developers don't have to worry, everything happens automatically.
- INTERPRETED or JUST-IN-TIME COMPILED:- Convert to machine code = compiling(happens inside the javascript engine).
- MULTI-PARADIGM:- An approach and mindset of structuring code, which will direct your coding style and technique.
- Procedural programming
- Object-oriented programming (OOP)
- Functional programming (FP)
- FIRST-CLASS FUNCTIONS:-functions are simply treated as variables. We can pass them into other functions, and return them from functions.
- EVENT LOOP CONCURRENCY MODEL:-
---> Concurrency model: how the JavaScript engine handles multiple tasks
happening at the same time.
---> JavaScript runs in one single thread, so it can only do one thing at a time.Why do we need that?
---> Sounds like it would block the single thread. However, we want non-blocking behavior!So what about a long-running task?
---> By using an event loop: takes long running tasks, executes them in the “background”, and puts them back in the main thread once they are finished.How do we achieve that?
WHAT IS A JAVASCRIPT ENGINE?
Simple, A program that executes JavaScript code. Example: v8 engine. There is a lot of JavaScript Engine according to the browser like Google Chrome (v8), SpiderMonkey (Firefox), Chakra (IE, Edge), and so on.
As you may hear before, JavaScript is an interpreted programming language. It means that source code isn’t compiled into binary code prior to execution.
How your computer can understand what to do with a plain text script?
That’s the job of a JavaScript engine. JavaScript engine is simply a computer program that executes JavaScript code. JavaScript engines are inbuilt in all modern browsers today. When the JavaScript file is loaded in the browser, the JavaScript engine will execute each line of the file from top to bottom (to simplify the explanation we are avoiding hoisting in JS). JavaScript engine will parse the code line by line, convert it into machine code and then execute it.
Every browser has its own JavaScript engine but the most well-known engine is Google’s V8. The V8 engine powers Google Chrome but also Node.js which is the JavaScript Runtime.
The Engine consists of two main components:
- Memory Heap — this is where the memory allocation happens
- Call Stack — this is where your stack frames are as your code executes
THE BIGGER PICTURE: JAVASCRIPT RUNTIME
So far we have discussed the JavaScript engine, but the JavaScript engine doesn’t run in isolation. It runs inside an environment called JavaScript Runtime Environment along with many other components. JRE is responsible for making JavaScript asynchronous. It is the reason JavaScript is able to add event listeners and make HTTP requests asynchronously.
It is the JRE that makes JavaScript asynchronous and allows web developers to make HTTP requests asynchronously. JRE consists of several components:
- JavaScript Engine
- Web API
- Callback queue
- Event loop
- Event Table
THE CALLSTACK IN JAVASCRIPT
JavaScript is a single-threaded programming language, which means it has a single Call Stack. Therefore it can do one thing at a time.
The Call Stack is a data structure that records basically where in the program we are. If we step into a function, we put it on the top of the stack. If we return from a function, we pop off the top of the stack. That’s all the stack can do.
Let’s see an example. Take a look at the following code:
const name = "Ashish";
const first = () => {
let a = 1;
const b = second(7,9);
a = a + b;
return a;
}
function second(x,y) => {
var c = 2;
return c;
}
const x = first();
When the engine starts executing this code, the Call Stack will be empty. Running code on a single thread can be quite easy since you don’t have to deal with complicated scenarios that are arising in multi-threaded environments — for example, deadlocks.
But running on a single thread is quite limiting as well. Since JavaScript has a single Call Stack.
WHAT IS AN EXECUTION CONTEXT?
The environment in which a piece of JavaScript is executed. Stores all the necessary information for some code to be executed.
Exactly one global execution context (EC): Default context, created for code that is not inside any function (top-level).
One execution context per function: For each function call, a new execution context is created. (All together make the call stack)
JavaScript Concurrency Model and Event Loop
First of all, let's explain the terminology.
Concurrency — This means that you have multiple task queues on multiple processor cores/threads. But it’s completely different from Parallel execution, parallel execution wouldn’t contain multiple task Queues for Parallel cases we will need 1 CPU core/thread per task for complete parallel execution, which in most cases we can’t define. That’s why for modern software development Parallel programming sometimes means “Concurrency”, I know it’s strange, but obviously, it’s what we have for the moment (it depends on OS CPU/thread model).
Event Loop — Means single threaded infinite cycle which is making one task at a time and it’s not only making a single task queue, but it is also prioritizing tasks because with an event loop you have only one resource for execution (1 thread) so for executing some tasks right away you need prioritizing tasks. In some words, this programming approach is called Thread Safe Programming because only one task/function/operation could be executed at a time, and if you are changing something it would be already changed during the next task execution.
What happens when you have function calls in the Call Stack that take a huge amount of time in order to be processed? For example, imagine that you want to do some complex image transformation with JavaScript in the browser.
You may ask — why is this even a problem? The problem is that while the Call Stack has functions to execute, the browser can’t actually do anything else — it’s getting blocked. This means that the browser can’t render, it can’t run any other code, it’s just stuck. And this creates problems if you want nice fluid UIs in your app.
And that’s not the only problem. Once your browser starts processing so many tasks in the Call Stack, it may stop being responsive for quite a long time. And most browsers take action by raising an error, asking you whether you want to terminate the web page. You can read more about the concurrency and event loop in the below article.
If you enjoyed this article, kindly spread the word.