浏览器渲染过程
浏览器渲染
解析 HTML 文件,构建 DOM 树,同时浏览器主进程负责下载 CSS 文件
CSS 文件下载完成,解析 CSS 文件成树形的数据结构,然后结合 DOM 树合并成 RenderObject 树
布局 RenderObject 树 (Layout/reflow),负责 RenderObject 树中的元素的尺寸,位置等计算
绘制 RenderObject 树 (paint),绘制页面的像素信息
浏览器主进程将默认的图层和复合图层交给 GPU 进程,GPU 进程再将各个图层合成(composite),最后显示出页面
总结:css不会阻止DOM的解析,但是会阻止render树的构成
V8执行流程
须知:JS是运行在V8引擎(Chrome等)上
- JS通过Parse模块解析成AST树,AST会被Ignition转成ByteCode,并且解释执行
- 如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能
- 但是,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码,再由Ignition
V8执行JS细节
parse过程
- Blink会将源码交给V8引擎,Stream获取到源码并且进行编码转换
- Scanner会进行词法分析(lexical analysis),词法分析会将代码转换成tokens
- 接下来tokens会被转换成AST树,经过Parser和PreParser:
- Parser就是直接将tokens转成AST树架构
- PreParser称之为预解析,为什么需要预解析呢? [1] 这是因为并不是所有的JavaScript代码,在一开始时就会被执行。那么对所有的JavaScript代码进行解析,必然会影响网页的运行效率 [2] 所以V8引擎就实现了Lazy Parsing(延迟解析)的方案,它的作用是将不必要的函数进行预解析,也就是只解析暂时需要的内容,而对函数的全量解析是在函数被调用时才会进行; [3]比如我们在一个函数outer内部定义了另外一个函数inner,那么inner函数就会进行预解析
- 生成AST树后,会被Ignition转成字节码(bytecode),之后的过程就是代码的执行过程(后续会详细分析)
JavaScript的执行过程
名词解释:
- 执行上下文栈(Execution Context Stack,简称ECS)
- Global Execution Context(GEC)
- 函数执行上下文(Functional Execution Context,简称FEC)
- Activation Object(AO)
GEC被放入到ECS中里面包含两部分内容
- 在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值(这个过程也称之为变量的作用域提升(hoisting))
- 在代码执行中,对变量赋值,或者执行其他的函数
FEC中包含三部分内容
- 在解析函数成为AST树结构时,会创建一个Activation Object(AO):AO中包含形参、arguments、函数定义和指向函数对象、定义的变量
- 作用域链:由VO(在函数中就是AO对象)和父级VO组成,查找时会一层层查找
- this绑定的值:这个我们后续会详细解析