持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
浏览器内核的组成
浏览器内核是有两部分组成:
- WebCore(渲染引擎): 负责HTML解析、布局、渲染等等相关的工作
- JavaScriptCore(JS引擎): 解析、执行JavaScript代码。
js引擎
JS引擎中最典型的就是V8引擎,以下关于JS引擎的机制我都会以V8来介绍
V8是用c++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。它实现ECMAScript和WebAssembly,并在window7或更高版本,macOS 10.12+和使用x64,IA-32, ARM或MIPS处理器的Linux系统上运行。V8可以独立运行,也可以嵌入到任何C++应用程序中。
1. V8引擎的执行原理
众所周知,计算机是不认识我们写的JavaScript源码的,它只认识机器语言,也就是0和1。因此特别需要一种工具能够将JavaScript源码转成cpu可以识别的机器语言,这时候JS引擎就开始工作了,下面介绍一下JS引擎是如何将JavaScript源码转成CPU能识别的机器语言的。
parse解析器: parse模块会将JavaScript代码转成AST树
- 如果函数没有被调用,那么是不会被转换成AST的
1.1 Igition解释器
会将AST转换成ByteCode(字节码)
- 同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算)
- 如果函数只调用一次,Ignition会解释执行ByteCode
1.2 TurboFan编译器
可以将字节码编译为CPU可以直接执行的机器码。
- 如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能。
- 但是,机器码实际上也会被还原成ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型)。之前优化的机器码并不能正确的处理运算,就会逆向地转成字节码
1.3 相关问题说明:
问题1: 不把JavaScript源码直接转成CPU能识别的机器语言,而是转成ByteCode?
答:在回答这个问题之前,我们先来看看字节码和机器码的区别
- 机器码,也叫机器语言指令,是计算机可以直接执行,并且执行速度最快的代码
- 字节码是一种包含执行程序、由一系列op代码、数据对组成的二进制文件。它是一种中间码,需要直译器转译后才能成为机器码的中间代码。
因为JavaScript运行在什么环境是不确定的,它可以运行在windows,macos, linux环境的浏览器中,也可以运行在node环境中。不同环境的CPU是不一样的,对应的机器指令也不一样。转化成字节码的好处就是不管在什么环境中,都可以执行,生成对应的cpu机器指令。
问题2: 上面的流程图里面已经有一个流程是可以转成字节码的(JavaScript源代码 --> parse --> AST抽象语法树 --> Ignition --> bytecode字节码 --> 运行结果),为什么还会有下面的流程呢?
答: 假如有个函数被重复调用了,如果只有这一个流程的话,它就会每次都需要从头开始去执行这个流程,这样的话是会非常降低性能的。如果可以将函数转成机器指令并且保存下来,然后需要调用这个函数的时候,就直接执行机器指令。这种方式适合多次调用函数,如果只调用一次函数,那么就没有必要转成机器指令然后保存起来。
2. V8引擎的解析原理
V8引擎的解析过程其实就是将JavaScript源码转成AST树。具体解析如图所示:
2.1 主要流程
- Blink将源码交给V8引擎,Stream获取到源码并且进行编码转换
- scanner会进行词法分析,词法分析之后会将代码转换为成词法单元(tokens)。如:var a = 2;。这段程序通常会被分解成为下面这些词法单元:var、a、=、2 、;。
- tokens会被转换为AST树,经过Parser和PreParser:Parser直接将tokens转成AST树架构,PreParser是预解析。var a = 2;的抽象语法树中可能会有一个叫作VariableDeclaration的顶级节点,接下来是一个叫作Identifier(它的值是a)的子节点,以及一个叫作AssignmentExpression的子节点。AssignmentExpression节点有一个叫作NumericLiteral(它的值是2)的子节点。
- 后面的流程就是上面的代码执行流程
2.2 相关概念
词法分析(lexical analysis): 将字符序列转成token序列的过程
- token是记号化(tokenization)的缩写
- 词法分析器(lexical analyzer, 简称lexer), 也叫扫描器(scanner)
语法分析(syntactic analysis, 也叫parsing)
- 语法分析器也可以称之为parser.