认识JS引擎
1. `高级编程语言`都有转化成`最终的机械指令`来执行的
2. 我们平时编写的js,无论你交给`浏览器或Node`执行,最后都是需要被CPU执行的
3. 但CPU只认识自己的指令集,实际上是机械语言,才能被CPU所执行
4. 所以我们需要JS引擎将JS代码翻译成CPU指令来执行
5. SpiderMonkey:第一款JS引擎,由Brendar Eick开发,也就是JS作者
6. Chakra:微软开发,用于IE浏览器
7. JavaScriptCore:WebKit中的JS引擎,Apple公司开发
8. V8:Google开发的强大JS引擎,帮助Chrome从众多浏览器中脱颖而出
9. 等等。。。。。
浏览器内核与JS引擎的关系
第一部分 WebCore:负责HTML解析、渲染布局等相关工作
第二部分 JavaScriptCore:解析执行JS代码
V8引擎原理
- V8是用
C++ 编写的Google开源高性能的JavaScript 和WebAssembly 引擎,用于Chrome和Node.js等 - 它实现
ECMAScript 和WebAssembly ,并在win7或更高版本,macOS10.12+版本和使用x64、IA-32、ARM或MIPS处理器的Linux系统上运行 - V8可以独立运行,也可以嵌入到任何
C++ 程序当中
工作流程图:
流程图分析:
- parse:对js代码进行解析,包括词法分析和语法分析
const name = "lisi";
tokens = [
{
type:"keyword",
value: const,
}
{
type:"identifier",
value: "name",
}
...
]
AST 树如下图所示:
const name = "lisi"; 对应的AST 树 const name = "lisi"; 对应的JSON 结构
{
"type": "Program",
"start": 0,
"end": 20,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 20,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 19,
"id": {
"type": "Identifier",
"start": 6,
"end": 10,
"name": "name"
},
"init": {
"type": "Literal",
"start": 13,
"end": 19,
"value": "lisi",
"raw": "\"lisi\""
}
}
],
"kind": "const"
}
],
"sourceType": "module"
}
- 扩展:
babel 将 ts 代码转换成 js 代码过程
ts ==> ast树 ==> 修改ast树 ==> generate code (生成代码) ==> js
ES6 ==> ast树 ==> ES5
- ignition:将
AST 树转换为bytecode 字节码
为什么不把 AST树 转换为 机械码0101 的形式?而要先转成字节码?
答:
代码的运行环境是不一定的,而不同的环境他有不同的CPU架构,
他们执行的机械指令是不一样的,而ignition他不知道该转换成什么机械指令的代码,
而bytecode字节码他相当于是跨平台的
v8引擎就会把`字节码`转换成对应的`汇编代码`然后再转换成相应平台(window、Linux)的CPU指令(0101)
- TurboFan:将ignition中执行次数比较多的代码,直接转换成对应的机械码(0101),提高性能
V8引擎架构
V8引擎本身的源码非常复杂,大概有超过100w行的C++代码,通过了解他的架构,可以知道他是怎么对JS执行的
Parse
Ignition
TurboFan
- 是一个
编译器 :可将ByteCode字节码编译成CPU可直接执行的机械码 - 如果一个函数被多次调用,那么就会被标记为
热点函数 ,那么就会经过TurboFan转换成优化后的机械码,提高代码的执行性能 - 如果后续执行函数的过程中,类型发生了改变(比如sum函数原来执行的number类型,后面执行变成了string类型),之前优化的机械码就不能正常的处理运算了,就会逆向的转换成字节码
- TurboFan的V8官方文档:https://v8.dev/blog/turbofan-jit
V8引擎的解析图
官方:
Blink(内核):解析HTML,解析过程中遇到JS就会下载下来以引流的方式传递给V8引擎
Stream(数据流):获取源码并进行编码转换
Scanner(扫描器):做词法分析的,会转换成很多 tokens
Parser(解析):将tokens转换成AST树
PreParser(预解析):预解析后再将数据交给Parser
因为并不是所有JS代码从一开始就会被执行。如果直接全部解析所有代码,会影响网页的运行效率,所以V8引擎就实现了Lazy Parsing(延迟解析)方案。
他的作用是将`不必要的函数进行预解析`,只解析暂时需要的内容(比如函数名),而对`函数的全量解析`是在`函数被调用的时候`才会进行
比如我们在fun函数里面定义一个fn函数,那么fn函数就会进行预解析
function fun(){
function fn(){
var name = "lisi"
}
}
|