Almost everyone has already heard of the V8 Engine as a concept, and most people know that JavaScript is single-threaded or that it is using a callback queue.
In this post, we’ll go through all these concepts in detail and explain how JavaScript actually runs. By knowing these details, you’ll be able to write better, non-blocking apps that are properly leveraging the provided APIs.
If you’re relatively new to JavaScript, this blog post will help you understand why JavaScript is so “weird” compared to other languages. And if you’re an experienced JavaScript developer, hopefully, it will give you some fresh insights on how the JavaScript Runtime you’re using every day actually works.
In this post, 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. We will discuss the following components:
- JavaScript Engine
- JavaScript Runtime Environment
- The Call Stack
- Concurrency and Event Loop
Let’s begin with the JavaScript engine.
The JavaScript Engine
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 the 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.
Browser engines
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
Any JavaScript engine always contains a call stack and a heap. The call stack is where our code is actually executed. Then the heap is an unstructured memory pool that stores all the objects that our application needs.
The 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.
JRE is just like a container which consists of the following components:
- JS Engine
- Web API
- Callback Queue or message queue
- Event Table
- Event loop
And then, we have the so popular event loop and the callback queue.
The Call Stack
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 wherein 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:
function multiply(x, y) { return x * y; }function printSquare(x) { var s = multiply(x, x); console.log(s); }printSquare(5);
When the engine starts executing this code, the Call Stack will be empty. Afterwards, the steps will be the following:
Each entry in the Call Stack is called a Stack Frame.
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.
Concurrency & the Event Loop
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.
Happy Learning …