1.用处
- chrome浏览器的引擎
- Nodejs的运行时环境
- electron的底层引擎
2.什么是V8引擎
- 是用C++编写的Google开源高性能JS和WebAssembly引擎
- 简而言之:是一个接收JS代码,编译代码然后执行的C++程序,编译后的代码可以在多种操作系统,多种处理器上运行
主要的工作:
- 编译和执行JS代码
- 处理调用栈
- 内存的分配
- 垃圾的回收
3.溯源
大部分JS引擎在编译和执行JS代码都会用到三个重要的组件:
- 解析器
- 负责将JS源代码解析成抽象语法树AST
- 解释器
- 负责将AST解释成字节码bytecode
- 也有直接解释执行bytecode的能力
- 编译器
- 负责编译出运行更加高效的机器代码
早期的V8引擎是如何编译和执行JS代码的:
在V8早期5.9版本之前,V8引擎没有解释器,却有两个编译器:
- JS由解析器解析后,生成AST抽象语法树
- 然后由编译器(Full-codegen)直接使用AST来编译出机器代码,而不进行任何中间转换
- Full-codegen又称基准编译器,因为它生成的是一个基准的未被优化的机器代码
- 还有另一个编译器(Crankshaft)——优化编译器:用来优化代码,提升性能
缺陷:
- 生成的机器码会占用大量的内存
- 缺少中间的字节码,很多性能优化策略无法实施——V8性能提升缓慢
- 无法很好的支持和优化JS的新语法特性
4.目前的V8引擎
- 网页初始化解析执行JS的时间缩短了,网页能够更快的onload
- 在生成的优化机器代码时,不需要从源码重新编译,而使用字节码,并且当需要回退字节码时,只需要回归到中间层的字节码解释执行就可以了
5.V8引擎中处理JS过程中的一些优化策略
- 如果函数只是声明而未被调用,则不会被解析生成AST
- 函数如果只被调用一次,bytecode直接被解释执行
- 函数被调用多次,可能会被标记为热点函数,可能会被编译成机器代码——提高代码的执行性能。
- 之后执行这个函数时,就直接运行优化后的机器代码
- 随着JS代码的不断执行,会有更多的代码被标记为热点代码,也就会产生更多的机器代码
- 此时会有一个问题:回退字节码。
- 造成的原因是:如一个sum函数,参数是a,b,多次调用传入整数,且被识别为热点函数,解释器将收集到参数和函数信息编译成优化后的机器码,这里就会假定了sum函数的参数就是整形的
- 但是如果某次你传入的不是整数,而是字符串,机器不知道如何处理字符串类型的参数,此时就会deoptimization(回退字节码)
- 总结:不要把一个变量类型变来变去,传入的参数的类型也要固定一下