The second principle of the browser: stand in the browser’s perspective, analysis of JavaScript execution mechanism; Take an in-depth look at Google’s JavaScript engine V8, analyze its execution process, and explain in detail how data is stored and recycled in JavaScript to help you build high performance and memory saving Web applications.
07. Variable promotion
08. The call stack
Compile implementation
- When JS executes global code, it compiles the global code and creates the global execution context.
- When a function is called, the code inside the function body is compiled, creating the function execution context. Normally, after the execution of a function is complete, the created function execution context is destroyed.
- The eval function (when executed?) The code is also compiled and the execution context is created.
Console.trace () prints the current function call relationship.
var a = 2;
function add(b, c) {
return b + c;
}
function addAll(b, c) {
var d = 10;
result = add(b, c);
return a + result + d;
}
addAll(3, 6);
Copy the code
Block level scope
Solve JS design defects such as variable promotion, variable coverage and variable pollution.
scope
The area of a program where variables are defined and where the lifetime of the variables is determined. Generally speaking, scope is the accessible scope of variables and functions, that is, scope controls the visibility and life cycle of variables and functions.
Global scope
It can be accessed anywhere in the code, and its life cycle follows the life of the page.
Function scope
A variable or function defined inside a function that can only be accessed inside the function. After the function is executed, the variables defined inside the function are destroyed.
Block-level scope
A piece of code wrapped in a pair of braces.
JS puts block-level scope into lexical context. (At compile time, variables declared by let const are placed in the lexical environment, while variables declared by var are placed in the variable environment.)
10. Scope chains and closures
Lexical scope means that the scope is determined by the position of the function declaration in the code and is static, independent of the function call.
closure
In JavaScript, according to the rules of lexical scope, an inner function can always access the variables declared in its outer function. When an inner function is returned by calling an outer function, the variables referenced by the inner function remain in memory even after the outer function has finished executing. Let’s call this set of variables a closure. For example, if the external function is foo, then the set of variables is called the closure of the foo function.
11. this
This has little to do with scope chains. There is a this in each execution context.
- When a function is called normally, this refers to the window; strictly, this is undefined;
- When a function is called as a method of an object, this in the function is the object;
- You can explicitly set this for the function execution context using the call, apply, and bind methods.
- Nested functions in which this does not inherit the this value of the outer function (solution: self saves the outer this or arrow function);
- The callback delayed by setTimeout is a method of an object, in which the this keyword points to the window;
- The constructor’s this points to the new object.
Stack space and heap space
Language type
- Static language: a language that requires a variable data type to be determined before use. C, C++, Java
- Dynamic languages: languages in which data types need to be checked during runtime. JS, PHP, Python, Ruby, VB
- Weakly typed languages: languages that support implicit type conversions. C, C++, JS, PHP, VB
- Strongly typed languages: languages that do not support implicit type conversions. Java, Ruby, Python
The stack
Raw type data is stored on the stack. (variable name: variable value) (a: 1) (user: 1003)
The heap
Reference type data is stored in the heap. (1003: {name: ‘JKB ‘, age: 2})
Talk about the closure
Closure (foo); / / Closure (foo); / / Closure (foo); / / Closure (foo);
13. Recycling
C, C++ : With manual reclamation, the code controls when memory is allocated and when memory is destroyed.
Javascript, Java, Python: Use garbage collectors to release generated garbage data.
Call stack data collection
After the function completes execution, the JS engine destroys the execution context held by the function on the stack by moving the ESP (the pointer to the current execution state) down. When the new function execution context is pushed, the original execution context is overridden directly.
Data collection in the heap
When the function completes, stack memory is freed. However, the heap space used by the objects in the function is still unfreed, which requires THE JS garbage collector.
V8
Region of two heaps
- New generation: stores objects with short survival time, and the capacity is 1 to 8 meters.
- Old generation: objects stored for a long time.
Two types of garbage collectors
- Secondary garbage collector: mainly responsible for the new generation of garbage collection.
- Main garbage collector: mainly responsible for old generation garbage collection.
Co-execution process
- Marks active and inactive objects in the space. Live objects are objects that are still in use, and inactive objects are objects that can be garbage collected.
- Reclaim memory occupied by inactive objects. That is, objects marked as recyclable in memory are uniformly cleaned up after the marking is complete.
- Memory consolidation. After objects are reclaimed frequently, there is a large amount of discontinuous space — memory fragmentation — that needs to be cleaned up as a final step. (Main garbage collector)
Secondary garbage collector
The New generation uses the Scavenge algorithm to split space in half into object areas and free areas. New objects are stored in the object area. When the object area is full, a garbage collection operation is performed.
- Mark the garbage in the object area, and then enter the garbage cleaning stage.
- The para-garbage collector copies living objects to the free area and arranges them in an orderly order (no memory fragmentation);
- After the replication is complete, roles are reversed in the object area and idle area.
- Objects that survive two garbage collections are moved to the old area.
Main garbage collector
The characteristics of objects in old area: occupy large space and live for a long time.
Mark-sweep algorithm
- Garbage marking process: Start from a set of root elements, traverse, can reach called active objects, not to reach the garbage data.
- Garbage removal process: The recyclable objects are cleaned directly.
Mark-compact algorithm
Mark the same process, then move all living objects to one end, and finally clean up the memory directly outside the end boundary.
The pause
JS and garbage collection are run on the main thread. Once garbage collection is performed, the JS script will pause and resume script execution after garbage collection is completed. This behavior is called total pause.
In order to reduce the lag caused by garbage collection in old Holy Land, V8 divides the marking process into sub-marking processes, and at the same time allows the garbage collection marking and JS application logic to alternate until the marking is complete. This algorithm is called incremental marking algorithm.
Compilers and interpreters
The compiler
Compiled languages, before the program is executed, the compiler compiles the source code into a binary file. Each time the program is run, the binary file is directly run without further compilation. Such as C, C++, GO
Workflow:
- Source code lexical analysis, syntax analysis >> AST;
- AST;
- Intermediate code code optimization >> binary files, directly executed.
The interpreter
The program needs to be dynamically interpreted and executed by an interpreter each time it is run. Such as Python, JS.
Workflow:
- Source code lexical analysis, syntax analysis >> AST;
- Byte code, explain execution.
AST
JS executes the first step of the code, generating the AST and the execution context.
- Lexical analysis: breaking up a line of code into tokens (e.g. keyword, identifier, Assignment, literal string…) ;
- Syntax analysis, the generated token data, according to the syntax rules into AST, if the source code complies with the syntax rules will be successfully completed, if there is a syntax error will terminate and throw “syntax error”.
The bytecode
JS performs the second step of the code, generating bytecode.
- The interpreter Ignition generates bytecode from AST.
- The interpreter Ignition explains executing bytecode point by point. When hot code is found (repeated multiple times), the TurboFan compiler in the background compiles it into efficient machine code and saves it for later use.
Bytecode is intermediate between AST and machine code and requires the interpreter to convert it to machine code for execution. Less memory footprint than machine code.
The technique of pairing bytecode with an interpreter and compiler is called just-in-time compilation (JIT).
JS performance optimization
- Improve the execution speed of a single script to avoid long JS tasks occupying the main thread.
- Avoid large inline scripts.
- Less JS file capacity.
The attached:
How Babel works
First, the ES6 source code is converted into AST, and then the AST of ES6 syntax is converted into AST of ES5 syntax, and finally the JS source code is generated using THE AST of ES5.
WebAssembly
Assembly assembly.
A technical solution in which code is written in a non-JS programming language and runs in a browser.
Write code in C, C++, Rust, compile it into a. Wasm file using LLVM (compiler toolchain) (which can be loaded in JS).
JS interpreter and compiler
Translate JS code into machine language.
- Interpreter: The translation process is done line by line, executed line by line.
- Compiler: Perform pre-translation.
The monitor
Part of the JS engine. Monitor code while JS is running, keeping track of how many times code snippets are run and the data types used. Those that run a few times are marked “warm” and handed over to the base compiler (slightly faster); Those that run too many times are marked as “hot” and handed to the optimized compiler (which speeds up considerably).
JS vs WebAssembly
JS: Download >>> parse >>> compile + optimize >>> re-optimize >>> Execute >>> Garbage collection
WebAssembly: Download >>> Parse >>> compile + optimize >>> Execute
- Download: The WebAssembly file is smaller than the JS file for the same function.
- Parse: JS source code is first parsed into an abstract syntax tree, then required code is converted to bytecode, and unneeded stubs are created. WebAssembly is bytecode and only needs to be parsed and determined for errors.
- Compile + optimize: JS dynamic type language, which is compiled during execution. The same code may be re-compiled due to different data types. WebAssembly bytecode does not need to determine data types at run time.
- Re-optimize: JS code is re-optimized if the runtime assumption is incorrect. The WebAssembly type explicitly does not need to be retuned.
- Execute: WebAssembly is designed for compilers to provide machine-appropriate instructions that run faster.
- Garbage collection: The JS engine uses the garbage collector to collect garbage automatically (with no control over timing). WebAssembly does not support garbage collection and memory needs to be managed manually
series
One of the principles of the browser: look at it in general