
How JS Works: Overview of the engine, runtime mechanisms, call stack
- Transfer
The popularity of JavaScript is growing, its capabilities are used at different levels of technology stacks used by developers and on many platforms. On JS they do frontend and backend, write hybrid and embedded applications, and much more.
Analysis of GitHub statistics shows that in terms of active repositories and push requests, JavaScript is in the first place, and in other categories it shows rather high positions. JavaScript Statistical Information with GitHub Another GitHub statistical information system can be found here , it confirms what was said above.

If many projects are tightly tied to JavaScript, it means that developers need to use everything that the language and its ecosystem gives them as efficiently as possible, striving, on the way to developing wonderful programs, to deeply understand the internal mechanisms of the language.
Oddly enough, there are many developers who regularly write in JavaScript, but do not know what is happening in its depths. The time has come to fix it: this material is devoted to a review of the JS engine using the example of V8, runtime mechanisms, and call stacks.
Almost everyone has heard, in the most general terms, about the V8 JS engine, and most developers know that JavaScript is a single-threaded language, or that it uses a callback function queue.
Here we will talk, at a fairly high level, about the execution of JS code. Knowing what actually happens when JavaScript is executed, you can write better programs that run without “hangs” and make reasonable use of the available APIs.
If you recently started writing in JavaScript, this material will help you understand why JS, in comparison with other languages, may seem rather strange.
If you are an experienced JS developer, we hope this material helps you better understand how what you use every day actually works.
V8 from Google is a well-known JS engine. It is used, for example, in the Chrome browser and in Node.js. Here's how it can be presented in a very simplified way:

Simplified representation of the V8 engine
In our diagram, the engine is presented consisting of two main components:
If we talk about the use of JavaScript in the browser, then there are APIs, for example, something like functions
Where do they come from? It turns out that reality looks a little more complicated than it might seem at first glance.

The engine, the event loop, the queue of callback functions and APIs provided by the browser
So, in addition to the engine, we still have a lot of things. Say - the so-called Web API that the browser provides us with - tools for working with the DOM, tools for executing AJAX requests, something like a function
JavaScript is a single-threaded programming language. This means that it has one call stack. Thus, at a certain point in time he can perform only one task.
The call stack is a data structure that, in simple terms, records information about the place in the program where we are. If we go into a function, we put a record about it at the top of the stack. When we return from the function, we pull the topmost element from the stack and find ourselves where we called this function from. This is all the stack can do.
Consider an example. Take a look at the following code:
When the engine is just starting to execute this code, the call stack is empty. After this, the following occurs:

Call stack during program execution
Each entry in the call stack is called a stack frame .
The call stack analysis mechanism, based on the call stack information, and the stack trace that is issued when an exception occurs, are based on the stack analysis mechanism. The stack trace is the state of the stack at the time of the exception. Take a look at the following code:
If you do this in Chrome (it is assumed that the code is in the file

Trace the stack after an error occurs
If the maximum stack size is reached, a so-called stack overflow will occur. This can happen quite simply, for example, with the thoughtless use of recursion. Take a look at this piece of code:
When the engine starts executing this code, it all starts with a function call

Stack overflow
At some point, however, the amount of data about the function calls will exceed the size of the call stack and the browser decides to intervene, giving an error:

Exceeding the maximum size of the call stack
The single-threaded code execution model makes life easier for the developer. He does not need to take into account complex schemes of interaction of software mechanisms, such as the possibility of mutual blocking of flows that arise in multi-threaded environments.
However, the execution of the code in single-threaded mode also has certain limitations. Given that JavaScript has one call stack, let’s talk about what happens when a program slows down.
What happens when a call stack has a function that takes a lot of time to complete? For example, imagine that you need to perform some kind of difficult image conversion using JavaScript in a browser.
“What is the problem here?” You ask. The problem is that as long as there is a function in the call stack, the browser cannot perform other tasks - it is blocked. This means that the browser cannot display anything on the screen, it cannot execute other code. He just stops. Similar effects, for example, are not compatible with interactive interfaces.
However, this is not the only problem. If the browser begins to handle heavy tasks, it may stop responding to any influences for quite some time. Most browsers in this situation throw an error asking the user if he wants to complete the script and close the page.

The browser suggests completing the page.
Users will definitely not like these things.
So, how do you perform heavy computing without blocking the user interface and without suspending the browser? The solution to this problem is to use asynchronous callback functions. This is a topic for another discussion.
In general terms, we looked at the design of the JS engine, runtime mechanisms, and the call stack. Understanding the concepts presented here can improve the quality of the code.
Dear readers! This material is the first in a series of How JavaScript Works from the SessionStack blog . The second one has already been published - dedicated to the features of V8 and code optimization techniques. Do you think it's worth translating it?
Analysis of GitHub statistics shows that in terms of active repositories and push requests, JavaScript is in the first place, and in other categories it shows rather high positions. JavaScript Statistical Information with GitHub Another GitHub statistical information system can be found here , it confirms what was said above.

If many projects are tightly tied to JavaScript, it means that developers need to use everything that the language and its ecosystem gives them as efficiently as possible, striving, on the way to developing wonderful programs, to deeply understand the internal mechanisms of the language.
Oddly enough, there are many developers who regularly write in JavaScript, but do not know what is happening in its depths. The time has come to fix it: this material is devoted to a review of the JS engine using the example of V8, runtime mechanisms, and call stacks.
Overview
Almost everyone has heard, in the most general terms, about the V8 JS engine, and most developers know that JavaScript is a single-threaded language, or that it uses a callback function queue.
Here we will talk, at a fairly high level, about the execution of JS code. Knowing what actually happens when JavaScript is executed, you can write better programs that run without “hangs” and make reasonable use of the available APIs.
If you recently started writing in JavaScript, this material will help you understand why JS, in comparison with other languages, may seem rather strange.
If you are an experienced JS developer, we hope this material helps you better understand how what you use every day actually works.
JavaScript engine
V8 from Google is a well-known JS engine. It is used, for example, in the Chrome browser and in Node.js. Here's how it can be presented in a very simplified way:

Simplified representation of the V8 engine
In our diagram, the engine is presented consisting of two main components:
- Heap (Memory Heap) - the place where the allocation of memory.
- The Call Stack is where the so-called stack frames fall into the process of executing the code.
Runtime mechanisms
If we talk about the use of JavaScript in the browser, then there are APIs, for example, something like functions
setTimeout
that almost every JS developer uses. However, these APIs are not provided by the engine. Where do they come from? It turns out that reality looks a little more complicated than it might seem at first glance.

The engine, the event loop, the queue of callback functions and APIs provided by the browser
So, in addition to the engine, we still have a lot of things. Say - the so-called Web API that the browser provides us with - tools for working with the DOM, tools for executing AJAX requests, something like a function
setTimeout
, and much more.Call stack
JavaScript is a single-threaded programming language. This means that it has one call stack. Thus, at a certain point in time he can perform only one task.
The call stack is a data structure that, in simple terms, records information about the place in the program where we are. If we go into a function, we put a record about it at the top of the stack. When we return from the function, we pull the topmost element from the stack and find ourselves where we called this function from. This is all the stack can do.
Consider 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 is just starting to execute this code, the call stack is empty. After this, the following occurs:

Call stack during program execution
Each entry in the call stack is called a stack frame .
The call stack analysis mechanism, based on the call stack information, and the stack trace that is issued when an exception occurs, are based on the stack analysis mechanism. The stack trace is the state of the stack at the time of the exception. Take a look at the following code:
function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
foo();
}
function start() {
bar();
}
start();
If you do this in Chrome (it is assumed that the code is in the file
foo.js
), we will see the following stack information: 
Trace the stack after an error occurs
If the maximum stack size is reached, a so-called stack overflow will occur. This can happen quite simply, for example, with the thoughtless use of recursion. Take a look at this piece of code:
function foo() {
foo();
}
foo();
When the engine starts executing this code, it all starts with a function call
foo
. This is a recursive function that does not contain a condition for terminating a recursion. She calls herself uncontrollably. As a result, at each execution step, information about the same function is added to the call stack over and over again. It looks something like this: 
Stack overflow
At some point, however, the amount of data about the function calls will exceed the size of the call stack and the browser decides to intervene, giving an error:

Exceeding the maximum size of the call stack
The single-threaded code execution model makes life easier for the developer. He does not need to take into account complex schemes of interaction of software mechanisms, such as the possibility of mutual blocking of flows that arise in multi-threaded environments.
However, the execution of the code in single-threaded mode also has certain limitations. Given that JavaScript has one call stack, let’s talk about what happens when a program slows down.
Concurrent code execution and event loop
What happens when a call stack has a function that takes a lot of time to complete? For example, imagine that you need to perform some kind of difficult image conversion using JavaScript in a browser.
“What is the problem here?” You ask. The problem is that as long as there is a function in the call stack, the browser cannot perform other tasks - it is blocked. This means that the browser cannot display anything on the screen, it cannot execute other code. He just stops. Similar effects, for example, are not compatible with interactive interfaces.
However, this is not the only problem. If the browser begins to handle heavy tasks, it may stop responding to any influences for quite some time. Most browsers in this situation throw an error asking the user if he wants to complete the script and close the page.

The browser suggests completing the page.
Users will definitely not like these things.
So, how do you perform heavy computing without blocking the user interface and without suspending the browser? The solution to this problem is to use asynchronous callback functions. This is a topic for another discussion.
Summary
In general terms, we looked at the design of the JS engine, runtime mechanisms, and the call stack. Understanding the concepts presented here can improve the quality of the code.
Dear readers! This material is the first in a series of How JavaScript Works from the SessionStack blog . The second one has already been published - dedicated to the features of V8 and code optimization techniques. Do you think it's worth translating it?
[Advise reading] The other 19 parts of the cycle
Part 1: Overview of the engine, runtime mechanisms, call stack
Part 2: About the V8 internal device and code optimization
Part 3: Memory management, four types of memory leaks and their fight
Part 4: Event loop, asynchronism and five ways to improve the code using async / await
Part 5: WebSocket and HTTP / 2 + SSE. What to choose?
Part 6: Features and scope of WebAssembly
Part 7: Web workers and five scenarios for their use
Part 8: Service workers
Part 9: Web push notifications
Part 10: Tracking changes in the DOM using MutationObserver
Part 11:Web page rendering engines and tips for optimizing their performance
Part 12: Network browser subsystem, optimizing its performance and security
Part 12: Network browser subsystem, optimizing its performance and security
Part 13: Animation using CSS and JavaScript
Part 14: How JS works: abstract syntax tree parsing and optimization
Part 15: How does JS: classes and inheritance, transpilyatsiya in Babel and TypeScript
Part 16: How does JS: storage systems
Part 17: How does JS: Shadow DOM technology and ee components
Part 18:How JS Works: WebRTC and P2P Communication Mechanisms
Part 19: How JS Works: User Elements
Part 2: About the V8 internal device and code optimization
Part 3: Memory management, four types of memory leaks and their fight
Part 4: Event loop, asynchronism and five ways to improve the code using async / await
Part 5: WebSocket and HTTP / 2 + SSE. What to choose?
Part 6: Features and scope of WebAssembly
Part 7: Web workers and five scenarios for their use
Part 8: Service workers
Part 9: Web push notifications
Part 10: Tracking changes in the DOM using MutationObserver
Part 11:Web page rendering engines and tips for optimizing their performance
Part 12: Network browser subsystem, optimizing its performance and security
Part 12: Network browser subsystem, optimizing its performance and security
Part 13: Animation using CSS and JavaScript
Part 14: How JS works: abstract syntax tree parsing and optimization
Part 15: How does JS: classes and inheritance, transpilyatsiya in Babel and TypeScript
Part 16: How does JS: storage systems
Part 17: How does JS: Shadow DOM technology and ee components
Part 18:How JS Works: WebRTC and P2P Communication Mechanisms
Part 19: How JS Works: User Elements