JavaScript Runtime
As JavaScript is getting more and more popular, teams are using it on many levels like frontend, backend, embedded devices etc. As per GitHut stats, JavaScript is top in terms of active repositories and total pushes. So it is important to understand the basic building blocks of JavaScript and how they play together. This post is meant to understand the basics of JavaScript.
JavaScript Engine
A JavaScript Engine is software or an interpreter which executes the JavaScript code. A JavaScript engine can be implemented as a standard interpreter or just-in-time compiler that compiles JavaScript to byte code. JavaScript engines are typically developed by web browser vendors, and every major browser has one.
Below is the list of popular JavaScript engines.
For this tutorial, we will use the reference of the V8 engine. Below is a simplified view of the engine.
The engine consists of two main components:
1. Memory heap: It is a section of unstructured memory that is used for the allocation of objects and variables.
2. Call Stack: As the code executes stack frames gets added to the call stack. We will discuss Call Stack shortly.
There are many APIs that we regularly use in the browser(e.g. DOM), but those APIs are not provided by the engine. Web APIs like DOM, AJAX, and setTimeout etc are provided by the browsers. Also, browsers provide a popular event loop and callback queue.
The Call Stack
JavaScript is a single-threaded programming language. It can do one thing at a time. It has a single call stack.
The Call Stack is a data structure which records where in the program we are. If we step into a function, then it is added to the top of the stack. When we return from a function, it is removed from the stack.
Let us take an example of the below code.
领英推荐
function add(x, y) {
?return x + y;
}
function addAndPrint(x, y) {
?let temp = add(x, y);
?console.log(temp)
}
addAndPrint(10, 12)
When the engine starts the call stack is empty. Afterwards, the below steps are getting recorded in the call stack.
Each entry in the stack is called a Stack Frame.
When an exception occurs, the stack trace is constructed using the state of the call stack. Consider the below code.
function foo() {
?throw new Error('Session Stack Info.')
}
function boo() {
?foo()
}
function play() {
?boo()
}
play();
Browser logs below stack trace when exception occurs in above code.
Stack Overflow:
Running a code on a single thread is easy but simple errors in code can result in consuming maximum call stack size. Consider the below code that uses recursion.
function koo() {
? koo();
}
koo();
When the JavaScript engine starts executing the code it will start calling the function Koo. Due to recursion, the function will start calling itself without any termination condition. The same function will get added to the call stack again and again. When the call stack size exceeds the permissible size browser decides to take action and throws an exception like below.
Concurrency issue:
When you have function calls in the call stack that takes a huge amount of time to process a request then the browser can not do anything else and it will get stuck. This will create a problem when you want to build fluid UIs. Sometimes if a request is getting longer time the browser takes action asking if you want to terminate the page. Which results into very bad user experience.
If we want to write code that performs heavy operations without making UI unresponsive then asynchronous callbacks can be used. We will discuss async programming in the next article.