认识 V8 引擎( 二 )

1.2.2.从DOM树到构建WebKit绘图上下文

  1. CSS文件被CSS解释器解释成内部表示;
  2. CSS解释器完成工作后,在DOM树上附加样式信息,生成RenderObject树;
  3. RenderObject节点在创建的同时,WebKit会根据网页层次结构构建RenderLayer树,同时构建一个虚拟绘图上下文 。
1.2.3.绘图上下文到最终图像呈现
  1. 绘图上下文是一个与平台无关的抽象类,它将每个绘图操作桥接到不同的具体实现类,也就是绘图具体实现类;
  2. 绘图实现类也可能有简单的实现,也可能有复杂的实现,软件渲染、硬件渲染、合成渲染等;
  3. 绘图实现类将2D图形库或者3D图形库绘制结果保存,交给浏览器界面进行展示 。
上述是一个完整的渲染过程,现代网页很多都是动态的,随着网页与用户的交互,浏览器需要不断的重复渲染过程 。
1.3.JavaScript引擎
认识 V8 引擎

文章插图
引擎执行流程
JavaScript本质上是一种解释型语言,与编译型语言不同的是它需要一边执行一边解析,而编译型语言在执行时已经完成编译,可直接执行,有更快的执行速度(如上图所示) 。JavaScript代码是在浏览器端解析和执行的,如果需要时间太长,会影响用户体验 。那么提高JavaScript的解析速度就是当务之急 。JavaScript引擎和渲染引擎的关系如下图所示:
认识 V8 引擎

文章插图
JS引擎与渲染引擎的关系
JavaScript语言是解释型语言,为了提高性能,引入了Java虚拟机和C++编译器中的众多技术 。现在JavaScript引擎的执行过程大致是:
源代码-→抽象语法树-→字节码-→JIT-→本地代码(V8引擎没有中间字节码) 。一段代码的抽象语法树示例如下:
function demo(name) {console.log(name);}抽象语法树如下:
认识 V8 引擎

文章插图
抽象语法树
V8更加直接的将抽象语法树通过JIT技术转换成本地代码,放弃了在字节码阶段可以进行的一些性能优化,但保证了执行速度 。在V8生成本地代码后,也会通过Profiler采集一些信息,来优化本地代码 。虽然,少了生成字节码这一阶段的性能优化,但极大减少了转换时间 。
但是在2017年4月底,v8 的 5.9 版本发布了,新增了一个 Ignition 字节码解释器,将默认启动,从此之后将与JSCore有大致相同的流程 。做出这一改变的原因为:(主要动机)减轻机器码占用的内存空间,即牺牲时间换空间;提高代码的启动速度;对 v8 的代码进行重构,降低 v8 的代码复杂度(V8 Ignition:JS 引擎与字节码的不解之缘 - CNode技术社区) 。
JavaScript的性能和C相比还有不小的距离,可预见的未来估计也只能接近它,而不是与它相比,这从语言类型上已经决定 。下面将对V8引擎进行更为细致的介绍 。
2.V8引擎V8引擎是一个JavaScript引擎实现,最初由一些语言方面专家设计,后被谷歌收购,随后谷歌对其进行了开源 。V8使用C++开发,,在运行JavaScript之前,相比其它的JavaScript的引擎转换成字节码或解释执行,V8将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能 。有了这些功能,JavaScript程序在V8引擎下的运行速度媲美二进制程序 。V8支持众多操作系统,如windows、linux、Android等,也支持其他硬件架构,如IA32,X64,ARM等,具有很好的可移植和跨平台特性 。V8项目代码结构如下:
认识 V8 引擎

文章插图
代码结构
2.1.数据表示JavaScript是一种动态类型语言,在编译时并不能准确知道变量的类型,只可以在运行时确定,这就不像c++或者java等静态类型语言,在编译时候就可以确切知道变量的类型 。然而,在运行时计算和决定类型,会严重影响语言性能,这也就是JavaScript运行效率比C++或者JAVA低很多的原因之一 。
在C++中,源代码需要经过编译才能执行,在生成本地代码的过程中,变量的地址和类型已经确定,运行本地代码时利用数组和位移就可以存取变量和方法的地址,不需要再进行额外的查找,几个机器指令即可完成,节省了确定类型和地址的时间 。由于JavaScript是无类型语言,那就不能像c++那样在执行时已经知道变量的类型和地址,需要临时确定 。JavaScript 和C++有以下几个区别: