# 详细渲染过程

*文章部分图片来源于谷歌开发者文档和《How browsers work》*
## 文档解析

在Chrome开发者工具performence栏中可以看到parsing阶段：

![](/assets/screenhot9.png)

HTML parsing（HTML解析）的任务是根据HTML源文件生成`parse tree` 可以参照《编译原理》理解。对应到`词法分析`、`语法分析`。

![](/assets/image011.png)

webkit使用了两种非常有名的解析器生成器：用于创建词法分析器的**Flex**,以及用于创建解析器的**Bison（可用于CSS解析）**。Flex 的输入是包含标记的正则表达式定义的文件。Bison 的输入是采用 BNF 格式的语言语法规则。HTML的规则比较松散，不属于上下文无关文法，所以传统的自顶向下和自底向上语法分析都不适用。

### HTML DTD

`DTD`（Document Type Definition，文档类型定义），源于`SGML`，定义了合法的元素、属性和层次结构，可以把合法元素和属性理解为词法层面的，层次结构则限定了语法规则。HTML 4.01 中的 doctype 需要对 DTD 进行引用，因为 HTML 4.01 基于 SGML。而 HTML5 不基于 SGML，因此不需要对 DTD 进行引用，但是需要 doctype 来规范浏览器的行为（让浏览器按照它们应该的方式来运行）。这方面还可以参照`XML`,`XHTML`进行对比。

有关HTML4的文档类型定义规范：[https://www.w3.org/TR/html401/sgml/dtd.html](https://www.w3.org/TR/html401/sgml/dtd.html)

### 词法分析

采用状态机机制：

![](/assets/image019.png)

这个步骤和一般的编程语言词法分析过程是相同的。

### 构造解析树

在词法分析的同时，会进行解析树的构造，词法分析器分析得到一个节点都会交给构造器处理。解析树的构造同样采用状态机的机制，不断的接收新的token流，创建对应的标签元素，加入到解析树，改变状态。

![](/assets/2143330_1307526500FF6O.gif)

整个过程：

![](/assets/full-process.png)

## CSS parsing

CSS的文法属于上下文无关文法，可以使用自顶向下或自底向上的语法分析器。Webkit使用Flex和Bison解析生成器从CSS语法文件中自动生成解析器。Chrome 开发者工具performence相应的事件：

![](/assets/screenhot10.png)

最终得到这样一个语法分析树：

![](/assets/2143330_1307526506ZEHQ.png)

整个流程：

![](/assets/cssom-construction.png)

### 渲染树构建

![](/assets/render-tree-construction.png)

1. 从 DOM 树的根节点开始遍历每个可见节点。

2. * 某些节点不可见（例如脚本标记、元标记等），因为它们不会体现在渲染输出中，所以会被忽略。
   * 某些节点通过 CSS 隐藏，因此在渲染树中也会被忽略，例如，上例中的 span 节点---不会出现在渲染树中，---因为有一个显式规则在该节点上设置了“display: none”属性。
3. 对于每个可见节点，为其找到适配的 CSSOM 规则并应用它们。

4. 发射可见节点，连同其内容和计算的样式。



## Layout和Paint

当渲染对象被创建并添加到树中，它们并没有位置和大小，计算这些值的过程称为layout或reflow。所以在元素的大小和位置发生变化时都会触发layout。

浏览器针对Layout做了一定优化，如采用Dirty bit系统，只针对具有dirty标记的元素进行重新layout，即增量layout，且此过程是异步的；如果元素只是位置发生变化，其大小从缓存里读取，就不用再次计算。

绘制阶段，遍历渲染树并调用渲染对象的paint方法将它们的内容显示在屏幕上，绘制使用UI基础组件。当元素的位置和大小没有变化，如改变背景颜色等等，只会进行重新paint。Paint也采用dirty机制进行增量Paint。

参考资料：[http://taligarsiel.com/Projects/howbrowserswork1.htm](http://taligarsiel.com/Projects/howbrowserswork1.htm)

