Take a deep look at the most popular development languages of the day

JavaScript: Under the Hood

preface

Initially, JavaScript could only run in a Web browser, but with Node, JavaScript can now run on the server as well. While we may know when and where to use it, do we really know what’s going on behind the scenes when these scripts are executed?

Give yourself a pat on the back if you think you know a thing or two about JavaScript engines, but don’t be too quick to close this article; I’m sure you’ll still learn something from it.

JavaScript is a high-level language, but ultimately computers can understand only ones and zeros. So how does the code we write make sense to the computer? Mastering the basics of your programming language will enable you to write better code. In this article, we’ll explore just one question: How does JavaScript work?

Let’s get down to business

JavaScript engine

This is what this article will explore, and it is responsible for making the computer understand the JS code we write. A JavaScript engine is an engine that transforms our code into a machine-readable language. Without a JavaScript engine, the code you write would be nonsense to a computer. All programming languages, not just JavaScript, need a similar engine to translate this “gibberish” into language that makes sense for computers.

There are several JavaScript engines available today. You can check out all the JavaScript engines available at Wikipedia. They are also called ECMAScript engines, for reasons discussed below. Here are some JavaScript engines that you might use on a daily basis:

  • Chakra, Microsoft IE/Edge
  • SpiderMonkey, FireFox
  • V8, Chrome

In addition to other engines, you can search to understand. Next, we’ll take a closer look at these engines to see how they translate JavaScript files.

Inside the JavaScript engine

Now that we know that engines are necessary, we might be tempted to think:

Who invented the JavaScript engine?

The answer is, anyone can. It’s just a tool to analyze our code and translate it into another language. V8 is one of the most popular JavaScript engines and is used by Chrome and NodeJS. It is written in C++, an underlying language. But if everyone creates an engine, the scene is out of control.

Therefore, in order to establish a specification for these engines, ECMA’s standard was created, which mainly provides a specification for how to write the engine and all the functionality of JavaScript. This is why the new features are implemented in ECMAScript 6, 7, and 8. At the same time, the engine was updated to support these new features. Thus, we can check the availability of advanced JS functions in the browser in the development process.

Let’s explore the V8 engine further, because the basic concept is the same across all engines.

JavaScript V8 Engine

The diagram above shows the internal workflow of JS Engine. The code we enter will go through the following phases,

  1. Parser
  2. AST
  3. Interpreter to generate the ByteCode
  4. Profiler
  5. Compiler generates optimized code

Don’t be fooled by the above flow, as you’ll see in a few minutes that they all work together.

Before going any further into these stages, you need to understand the difference between Interpreter and Compiler.

Interpreter VS Compiler

In general, there are two ways to convert code into machine-readable language. The concepts we will discuss apply not only to JavaScript, but to most programming languages, such as Python, Java, etc.

  • Interpreter reads the code line by line and executes it immediately.
  • Compiler reads your entire code, makes some optimizations, and then generates the optimized code.

Let’s look at the following example.

function add(a, b) {
    return a+b
}
for(let i = 0; i < 1000; i++) {
    add(1 + 1)
}
Copy the code

The example above loops through 1000 calls to the add function, which adds the two numbers and returns the sum.

  1. Once Interpreter receives the above code, it reads it line by line and immediately executes it until the loop ends. Its job is simply to translate code in real time into something our computers can understand.
  2. If the recipient of this code isCompilerIt reads the entire program, analyzes the code we are executing and generates a machine language that the computer can understand. The process is like gettingX(Our JS file), and generateY(Machine language). If we use Interpreter executionY, will be obtained and executedXSame result.

As you can see from the figure above, ByteCode is only intermediate code and the computer still needs to translate it before it can be executed. But Interpreter and Compiler both translate source code into machine language, and the only difference is that the conversion process is different.

  • Interpreter converts the source code to the equivalent machine code line by line.
  • Compiler converts all source code to machine code at the outset.

If you want to learn more about the differences before, I recommend reading this article.

By the time you’ve read the recommended articles above, you probably already knowBabelIs actually a JS Compiler that accepts the new version of JS code you write and compiles down to browser-compatible JS code (the old version of JS code).

Pros and cons of Interpreter and Compiler

  • Interpreter has the advantage of executing code immediately without waiting for compilation. This is a great convenience for running JS in the browser, because no one wants to waste time waiting for the code to compile. However, it runs slowly when there is a lot of JS code to execute. Remember that little piece of code from the example above? 1000 function calls were made in the code. The function add is called 1000 times, but its output remains the same. But Interpreter is still performed line by line, which can be slow.
  • In the same case, Compiler can make some optimization by replacing the loop with 2 (since the add function executes 1 + 1 every time). The optimized code provided by Compiler can be executed in a shorter time.

To sum up, Interpreter starts executing code immediately, but does not optimize it. Compiler takes some time to compile the code, but produces code that is better for execution.

Ok, Interpreter and Compiler are necessary for this. Now let’s get back to the topic of JS engines.

So, given the pros and cons of both compilers and interpreters, what if we take advantage of both? This is where JIT(Just In Time) Compiler comes In. It is a combination of Interpreter and Compiler, and most browsers now implement it faster and more efficiently. The V8 engine also uses this feature.

JavaScript V8 Engine

And in the process,

  1. Parser is a Parser that identifies, analyzes, and classifies parts of programs using various JavaScript keywords. It can distinguish between code as a method and a variable.
  2. Then, the AST(Abstract Syntax tree) constructs the tree structure based on the Parser classification. You can use the AST Explorer to see the structure of the tree.
  3. The AST is then supplied to Interpreter to generate the ByteCode. As mentioned above, ByteCode is not the lowest level code, but it can be executed. At this stage, the browser works by executing ByteCode with the V8 engine, so the user doesn’t have to wait.
  4. At the same time, the Profiler looks for code that can be optimized and passes it to Compiler. While Compiler generates optimized code, the browser temporarily performs operations using ByteCode. Moreover, once Compiler generates the optimized code, the optimized code completely replaces the temporary ByteCode.
  5. In this way, we can take full advantage of Interpreter and Compiler. While Interpreter executes code, profilers look for code that can be optimized, and Compiler creates optimized code. The ByteCode code is then replaced with optimized lower-level code, such as machine code.

This simply means that performance will improve over time and there will be no blocking execution time.

About the ByteCode

As machine code, ByteCode is not understood and executed by all computers. It still requires middleware like a virtual machine or a Javascript V8 engine to convert it into machine-readable language. This is why our browser can perform ByteCode in Interpreter with the help of a JavaScript engine in the five stages described above.

So you can have another question,

Is JavaScript an interpreted language?

JavaScript is, but not entirely, an interpreted language. Brendan Eich originally created the JavaScript engine SpiderMonkey in the early days of JavaScript. The engine has an Interpreter that tells the browser how to execute the code. But now our engine includes not only Interpreter but also Compiler. Not only can our code be converted to ByteCode, but it can also be compiled to output optimized code. So technically, it all depends on how the engine is implemented.

This is how JavaScript engines work in general. You don’t need to learn JavaScript to understand this. Of course, you can write code without even knowing how JavaScript works. But a little behind-the-scenes knowledge might allow us to write better code.

Welcome to reprint, remember to indicate the author and source oh ~~