JavaScript Engine And Runtime
Understanding what happens behind the scenes in javascript execution
For you to become a competent JavaScript developer, you should have a basic understanding of how code is compiled and executed. In this article, we will explore how JavaScript works behind the scenes to compile our code.
Prerequisite
- Basic Knowledge of JavaScript
JavaScript Engine
Generally, JavaScript Engines are programs that execute JavaScript code and convert it into a language computer programs can understand.
Every browser has its engine, the most common being google's V8 engine - which powers google chrome and also Node.js.
Note: Other browsers have their engine. see here.
Components of the JavaScript Engine
JavaScript Engines are composed of two (2) components, namely;
- Call Stack
- Heap
Call Stack
This is where our code is executed using the execution context - which is where the code that is currently running is located, along with everything that aids its execution.
The Heap
This is an unstructured memory pool that stores all the objects that our application needs.
Diagram of the Javascript Engine.
How Is JavaScript Code Compiled to Machine code?
Before we go into how our code is compiled to machine code, let's note that a computer's processor can only understand 0s and 1s. Every single computer program needs to be converted into machine code and this can be done using compilation or interpretation.
Now let's examine the differences between compilation and interpretation to get a better grasp of each.
Compilation: A compilation is a process by which all of the code is converted into machine code at one time and written to a binary file, which is a file that stores information in bytes and can be interpreted by a computer as something other than textual characters.
Flowchart representing the steps in compilation
Interpretation: In this case, the interpreter runs through the source code, then executes it line by line. It involves just one step and doesn't require any portable file.
Flowchart representing the steps in interpretation
Having learned about interpretation and compilation, which technique does JavaScript use when executing the code? It uses Just-In-Time (JIT) Compilation.
Just-In-Time (JIT) Compilation:
While interpreted languages are usually much slower than compiled languages, this is not the case with JavaScript since it uses a Just-In-Time(JIT) compilation method for its execution, which is a combination of interpretation and compilation.
In JIT, the entire code is converted into machine code at once then it is executed immediately.
Flowchart representing the steps in Just-In-Time Compilation
Steps in Just-In-Time compilation
The following are steps used to carry out the JIT compilation;
As the JavaScript code enters the engine;
Step 1: The code gets parsed - parsing means reading the code. The code is parsed into a data structure called the abstract syntax tree (AST). The AST first splits up every line of code into pieces that are meaningful to the language (like the const
/ function
keyword) and saves all the pieces into the tree in a structured way. The AST also checks if there are syntax errors and the resulting tree is used to generate the machine code.
Note:
- You don't need to know what an AST looks like.
- Does the AST have anything to do with the DOM tree? ๐ซ No, the AST is just a representation of our entire code in the engine.
Step 2: The code gets compiled - The AST that is generated is compiled to machine code.
Step 3: Execution happens - Execution happens in the engines' call stack. JavaScript first creates an unoptimized version of machine code in the beginning, so it can start executing as fast as possible. In the background, the code is recompiled and optimized then the previous unoptimized version will be swapped with the most optimized version.
Note: All this happens in special threads that we can't access from our code.
JavaScript Runtime.
The Javascript runtime refers to the location where your javascript code is executed when you run it. Essentially it can be seen as a big box that contains all the necessary components for using JavaScript, in this case in the browser.
The heart of the JavaScript runtime is the JavaScript Engine.
Components of the JavaScript Runtime
Without the JavaScript engine, there is no Runtime, but the engine alone is not enough. In order for the runtime to work properly, it must contain other components, which are;
- JavaScript Engine
- Web APIs
- Callback queue
Web APIs
Web APIs are application programming interfaces for the Internet. Web APIs increase a browser's functionality. They are functionalities provided to the engine but are not part of the JavaScript language. JavaScript gets access to the Web APIs through the global window object.
Callback Queue
This is a data structure that contains all the callback functions that are ready to be executed. Callback queues, as their name suggests, are queues, so functions added to them are handled in a first-in-first-out order.
Diagram of the Javascript Runtime
let's take a practical example:
const burger = document.querySelector(".burger");
const navLinks = document.querySelector('.nav-links')
burger.addEventListener("click", () => {
navLinks.classList.add('hidden')
});
Here, we have a click event listener (which is also a callback function) attached to the burger element. The following are steps in which this code gets executed when the burger is clicked behind the scene;
Step 1: Callback function is put into the callback queue.
Step 2: When the call stack is empty, the callback function is passed into the call stack, so it can be executed. This is handled by the event loop.
The event loop
JavaScript's asynchronous programming relies on the event loop. The event loop checks if the call stack is empty, and if it is, takes the callback function and puts it into the call stack to be executed.
Note:
The event loop is essential for JavaScript non-blocking concurrency model.
Since JavaScript can be used outside the browser e.g. Node.js, the runtime environment varies. The runtime for Node.js consists of the engine, callback queue, multiple c++ bindings, and thread pool.
Conclusion
As a reader, if you don't understand how JavaScript works behind the scenes, I hope this article has been able to shed some light on the subject. Although it isn't a deep article, the knowledge alone is sufficient to help you understand how JavaScript works.