前言:v8引擎本身的源码是非常复杂的,大概有超过100w行c++的代码,这里不做具体解析,只是浅析一下V8引擎的的原理是怎样的,如何去执行js代码?
我们来看下官方对V8引擎的定义:
简单说一下就是:V8引擎是C++编写的开源引擎,用于
Chrome和Node.js去执行js代码,可以独立运行,也可以嵌入在C++应用程序中
那V8引擎是如何去执行js代码?
- 首先javaScript源代码,会经过
paser模块,被解析成AST抽象语法树(因为解释器并不认识javaScript代码)- 那在转成parse的这个过程中发生了什么呢?其实主要是词法分析和语法分析
词法分析:会把代码分成一个个不能细分的单词(token),这些token组成tokens数组 如const name="foo"分别是const、name、foo,这个过程是词法分析,按照单词的构成规则来拆分字符串成单词。我们来看下图 - 语法分析:把 token 进行组装,生成 AST,这个过程是语法分析,按照不同的语法结构,来把一组单词组合成对象。我们来一起看下图
这里附上AST语法解析官网链接 :传送门AST语法解析官网
- 那在转成parse的这个过程中发生了什么呢?其实主要是词法分析和语法分析
name对应:
"id": {
"type": "Identifier",
"start": 6,
"end": 10,
"name": "name"
},
foo对应:
"init": {
"type": "Literal",
"start": 11,
"end": 16,
"value": "foo",
"raw": "\foo\""
}
- 第二步会经过
lgnition解释器,将AST抽象语法树解释成字节码bytecode- 如果代码只执行一遍是直接通过lgniton解释成字节码,如果一个函数被调用很多次,那这个函数会被标记成热点函数(hot func),会经过turbofan,转成优化之后的机器码
- 如果一个热点函数在调用的过程中,类型发生了改变,那么还是要经过lgnition来进行deoptimited反优化,有机器码再转为字节码,然后再转为机器码进行运行由
v8引擎的架构
有三大模块,分别是:
- parse模块
将js源代码解析成AST抽象语法树 - lgnition
lgnition解释器:将AST抽象语法树解释成字节码
同时收集turbofan所需要的优化信息 - turtofan
turbofan是一个编译器:可以将字节码编译成CPU直接运行的机器码
如果一个函数被多次调用,那么会标记成热点函数,由turbofan直接编译成优化后的机器码来提升性能
问答环节
追问:这是为什么不直接转成机器码而要先转成字节码呢?
因为无法确定这个代码会运行在怎样的环境上(windows,mac,linux),不同环境的cpu架构不同,不同cpu架构能执行的机器指令不同,所以无法确定机器指令,所以才转化为字节码。字节码可以跨平台,转化为机器指令后就可以运行了
追问:这里抛出一个问题,为什么不通过lgnition直接编译成字节码呢?
因为lgnition解释器并不能直接认识s代码,需要先经过parse模块解析成抽象语法树
预告:
下个章节说JS的执行过程和执行上下文