📜 ⬆️ ⬇️

How JS Works: Overview of the Engine, Runtime Mechanisms, Call Stack

The popularity of JavaScript is growing, its capabilities are being used at various levels of technology applied by stack developers and on a variety of platforms. On JS, they make 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 quite high positions.


JavaScript statistics from GitHub
')
With another system of statistical information on GitHub can be found here , it confirms what was said above.

If a lot of projects are tightly tied to JavaScript, then developers need to use everything that gives them the language and its ecosystem as efficiently as possible, striving, in the way of developing wonderful programs, to a deep understanding of the internal mechanisms of the language.

Oddly enough, there are many developers who regularly write to 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, the execution time mechanisms, and the call stack.

Overview


Almost everyone has heard, in general terms, about the V8 JS engine, and most developers know that JavaScript is a single-threaded language, or that it uses a queue of callback functions.

Here we will talk, at a fairly high level, about executing JS code. Knowing what actually happens when you run JavaScript, you can write better programs that run without “hangs up” and intelligently use existing 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 will help you better understand how what you use every day actually works.

JavaScript engine


V8 from Google is a widely known JS engine. It is used, for example, in the Chrome browser and in Node.js. Here's how it is, very simply, you can imagine:


Simplified view of the V8 engine

In our scheme, the engine is presented consisting of two main components:


Runtime mechanisms


If we talk about the use of JavaScript in the browser, then there are APIs, for example, something like the setTimeout function 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 bit more complicated than it might seem at first glance.


Engine, event loop, callback function queue and API provided by browser

So, in addition to the engine, we still have a lot of things. Let's say - the so-called Web API, which the browser provides us with - tools for working with DOM, tools for performing AJAX requests, something like setTimeout function, and much more.

Call stack


JavaScript is a single-threaded programming language. This means that he has one call stack. Thus, at some point in time, he can perform only a single task.

The call stack is a data structure that, to put it simply, records information about the place in the program where we are. If we go to a function, we put an entry about it in the upper part of the stack. When we return from a function, we pull out the topmost element from the stack and find ourselves where we called this function. This is all that a 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 stack frame information analysis engine is based on the call stack, the stack trace issued when an exception occurs. 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 (assuming the code is in the foo.js file), we will see the following information about the stack:


Stack trace 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 code snippet:

 function foo() {   foo(); } foo(); 

When the engine starts to execute this code, it all starts with a call to the foo function. This is a recursive function that does not contain a condition for stopping recursion. She calls herself uncontrollably. As a result, at each step of the execution, information about the same function is added to the call stack again and again. It looks like this:

Stack overflow

At a certain point, however, the amount of data about the function calls will exceed the size of the call stack and the browser decides to intervene, producing an error:


Exceeding the maximum call stack size

The single-threaded code execution model makes a developer’s life easier. It does not need to take into account the complex interaction patterns of software mechanisms, such as the possibility of interlocking threads that occur in multi-threaded environments.

However, the execution of code in single-threaded mode also has certain limitations. Given that JavaScript has one call stack, let's talk about what happens when the program “slows down”.

Parallel code execution and event loop


What happens when there is a function in the call stack that needs a lot of time to execute? For example, imagine that you need to perform some kind of difficult image transformation using JavaScript in your browser.

“What is the problem?”, You ask. The problem is that as long as there is an executing function in the call stack, the browser cannot perform other tasks — it is blocked. This means that the browser can not display anything on the screen, can not execute other code. He just stops. Similar effects, for example, are incompatible with interactive interfaces.

However, this is not the only problem. If the browser begins to handle heavy tasks, it may stop responding to any impacts for quite a long time. Most browsers in this situation give an error asking the user whether he wants to complete the execution of the script and close the page.


Browser offers to complete page execution

Users just do not like these things.

So, how to perform heavy calculations without blocking the user interface and not suspending the browser? The solution to this problem is to use asynchronous callback functions. This is a topic for a separate discussion.

Results


We have, in general terms, considered the device JS-engine, mechanisms for execution time and call stack. Understanding the concepts outlined here allows you to improve the quality of the code.

Dear readers! This material is the first in the How JavaScript Works series from the SessionStack blog. The second has already been published - dedicated to the features of the V8 and code optimization techniques. In your opinion, is it worth it to translate?

Source: https://habr.com/ru/post/337042/


All Articles