preface
As a front-end developer, you can’t live without the browser, so why can the browser execute JavaScript code? Most of us probably don’t think about how the inside of the browser executes code, because the inside of the browser is like a black box to us. We just manipulate it and it gives us the final result. The following is a summary of some of the browser works as well as the browser internal kernel and JS engine implementation process, I hope to be useful to you.
1. How browsers work
How does the browser load the page when you type in what you’re looking for? And how is JavaScript code executed in the browser?
The general process can be observed in the following figure:
- First, the user enters the server address in the search bar of the browser to establish a connection with the server.
- The server returns the corresponding static resource (typically
index.html
); - Then, the browser gets
index.html
Then analyze it; - When CSS or JS files are encountered during parsing, it requests the server and downloads the corresponding CSS and JS files.
- Finally, the browser renders the page and executes the JS code.
So what happens when you type in the server address and hit Enter?
- The DOMAIN name is resolved into the corresponding IP address by DNS.
- An HTTP request is then sent to this IP address. The server receives the sent HTTP request, processes it, and responds.
- Eventually the browser gets what the browser responds to;
2. The browser kernel
The files that the browser downloads from the server are eventually parsed, so who helps parse them internally? This is where the browser kernel comes in. Different browsers are made up of different kernels. Here are a few common browser kernels:
- Gecko: Early use by Netscape and Mozilla Firefox;
- Trident: Developed by Microsoft, Internet Explorer has always been used, but the Edge core has moved to Blink;
- Webkit: Apple is based on KHTML and is open source. It is used in Safari and early in Google Chrome.
- Blink: Developed by Google based on Webkit, it is a branch of Webkit, currently used in Google Chrome, Edge, Opera, etc.
In fact, the browser kernel refers to the layout engine of the browser, also known as the browser engine, page rendering engine, or sample engine.
3. Browser rendering process
Once the browser has downloaded the file from the server, it needs to parse and render it as follows:
- The HTML Parser converts HTML parsing into a DOM tree;
- CSS Parser converts stylesheet parsing into A CSS rule tree;
- The conversion completes the DOM Tree and CSS rule Tree Attachment together, and generates a Render Tree;
- Note that the Render Tree is not immediately rendered, there is also a Layout operation in the middle, that is, the Layout engine;
- Why do I need a layout engine to operate on Render Tree? Layout is used to determine the location and effect of the display element because the state of the browser is different at different times (such as browser width).
- With the final Render Tree, the browser will do the Painting and then the Display;
- You can see that there is also a purple DOM triangle, which is actually js operations on the DOM;
- When PARSING HTML, if you encounter JavaScript tags, you stop parsing the HTML and load and execute JavaScript code instead.
So, who executes the JavaScript code? Here comes the JavaScript engine.
4. The JavaScript engine
Let’s start with two questions about JavaScript engines.
(1) Why do you need a JavaScript engine?
- First, we need to know that JavaScript is a high-level programming language, and all high-level programming languages need to be translated into final machine instructions to execute;
- We know that javascript code written can be executed by the browser or Node, and the underlying layer is ultimately handed over to the CPU.
- However, the CPU only knows its own instruction set, which is machine language, and the JavaScript engine’s main function is to help us translate JavaScript code into the instructions that the CPU can understand, and finally be executed by the CPU.
(2) What are JavaScript engines?
- SpiderMonkey: First JavaScript engine, developed by Brendan Eich (JavaScript author);
- Chakra: For Internet Explorer, developed by Microsoft;
- JavaScriptCore: a JavaScript engine built into Webkit, developed by Apple;
- V8: The most powerful and popular JavaScript engine today, developed by Google;
5. The relationship between browser kernel and JS engine
The Webkit kernel is used as an example.
-
Actually, Webkit consists of two parts:
- WebCore: responsible for HTML parsing, layout, rendering and other related operations;
- JavaScriptCore (JSCore) : Parsing and executing JavaScript code;
-
JavaScript code written in the applet is executed by JSCore, the engine used by the applet is JavaScriptCore:
-
Rendering layer: Webview to parse and render WXML, WXSS, etc.
-
Logic layer: JSCore parses and executes JS code;
-
The following is the official architecture diagram of the applet:
-
6. V8 engine
Here’s a closer look at the mighty V8 engine.
6.1. Principle of V8 engine
Let’s take a look at the official definition of V8:
-
V8 engine is Google’s open source high-performance JavaScript and WebAssembly engine written in C++ for Chrome, node.js, etc. It can be run independently or embedded in any C++ application.
-
So V8 isn’t just for JavaScript, it can be used with WebAssembly (a binary instruction format for stack-based virtual machines), and it runs on multiple platforms.
-
The following diagram briefly shows V8’s underlying architecture:
6.2.V8 Engine architecture
V8’s underlying architecture consists of three core modules (Parse, Ignition, and TurboFan), which are described in detail in the architecture diagram above.
(1) Parse module: Converts JavaScript code into an AST (abstract syntax tree).
-
This process mainly carries on the JavaScript source code lexical analysis and the grammar analysis;
-
Lexical analysis: Parse every word or symbol in your code to generate a lot of tokens.
-
For example, to parse the line const name = ‘curry’ :
// Const is parsed first. Since const is a keyword, the type is remembered as a keyword with a value of const tokens: [{type: 'keyword'.value: 'const'}]// Then name is parsed. Since name is an identifier, the type is recorded as an identifier with a value of name tokens: [{type: 'keyword'.value: 'const' }, { type: 'identifier'.value: 'name'}]// And so on... Copy the code
-
-
Grammar analysis: On the basis of lexical analysis, acquire each object in tokens, and then analyze the specific grammar according to their different types to generate AST.
-
The AST Explorer tool is used to Parse and Parse JavaScript code. The AST Explorer tool is used to Parse JavaScript code.
-
AST is used in many front-end scenarios, such as converting TypeScript code to JavaScript code, ES6 to ES5, and templates in Vue, which are converted into the corresponding AST and then regenerated into object code.
-
V8. dev/blog/scanne…
(2) Ignition module: an interpreter that converts the AST to ByteCode.
- Byte-code: A binary file containing an executable consisting of a sequence of OP code/data pairs, intermediate code.
- JS code is converted to AST so that the engine can manipulate it. JS code is ultimately converted to machine code for CPU execution, so why should it be converted to bytecode first?
- Because the environment in which JS runs is not certain, it may be Windows or Linux or iOS, and the machine instructions recognized by the CPU of different operating systems are also different. Bytecode is an intermediate code that is inherently cross-platform, and the V8 engine then compiles the bytecode into the corresponding machine instructions for execution by the CPU in the current environment.
- V8. dev/blog/igniti…
(3) TurboFan module: a compiler that compiles bytecode into machine code that the CPU understands.
- Before getting to TurboFan, consider the performance penalty of converting the AST into bytecode and then parsing it into machine instructions every time you execute code. Powerful V8 was already in mind, hence TurboFan’s library;
- TurboFan captures some of the information collected by Ignition. If a function is called multiple times in code, it is marked as a hot function, converted by TurboFan into optimized machine code, and executed directly when it is executed again, improving code performance.
- There’s another one in the picture
Deoptimization
The process, in fact, isMachine code is restored to ByteCodeFor example, the argument type passed to the hot spot function changes during the subsequent execution of the code (if the sum function is passed the argument of type number, it is an addition; If the sum function is passed a String parameter, it will do String concatenation.) The optimized machine code may not meet the requirements, and the bytecode will be reversed, and the bytecode will be compiled into the correct machine code for execution. - We can see from this that we can optimize the efficiency of our code by passing fixed types of arguments to functions, so TypeScript compiled JavaScript code performs better.
- See official documentation: v8. Dev /blog/ Turbof…
6.3.V8 Engine Execution Process
The V8 engine provides the following diagram for the Parse process. Finally, take a closer look at how the Parse process works.
- ①Blink kernel gives JS source code to V8 engine;
- ②Stream gets JS source code for encoding conversion;
- Scanner performs lexical analysis to convert codes into tokens;
- (4) After parsing, tokens are transformed into AST, through Parser and PreParser:
- Parser Transforms tokens into AST trees
- PreParser: Why do we need to prepare?
- Because not all JavaScript code executes at first, Parsing all of it at once would necessarily affect performance, V8 implemented Lazy Parsing, which preparsing unnecessary function code. The full parsing of a function takes place when the function is called.
- ⑤ After the AST is generated, it is converted to bytecode by Ignition, then to machine code, and finally to code execution.