Webkit 渲染引擎组成
- 渲染引擎由七部分组成:

从输入 URL 到页面完全展示,这段时间发生了什么?
- 从输入 URL 到页面展示大致分为以下四步。
- 浏览器引擎对 URL 进行解析,发起请求 -->
- TCP 三次握手,建立连接,浏览器客户端向服务端发送报文,传输数据 -->
- 进入后端服务,如 Apache,Node 服务等,后端根据 URL 执行后端逻辑,处理请求,响应报文-->
- 浏览器接收到返回信息,下载资源(html,css,js 等资源),开始解析。。
- 渲染引擎整个渲染过程如下:
渲染主流程
- 浏览器从接收到 html,css,js 等资源到用户看到界面要经历以下几个步骤:
- 解析(解析 HTML 生成 DOM 树,解析 CSS 生成 CSSOM 树),
- 渲染(将 DOM 树与 CSSOM 树合并在一起生成渲染树,具有一定视觉效果),
- 布局(计算位置等信息,为每个节点分配固定坐标),
- 绘制(遍历所有节点,由 UI 后端绘制)
First - 解析
- 浏览器获得资源后,也就是我们写的代码(HTML,CSS,JS),计算机是不认识的,它只认识 0、1 这种字节数据,浏览器接收到这些字节数据后会将字节数据转换为字符串。
- 当转换为字符后,浏览器创建了自定义的解析器来解析 HTML,这种解析算法会对 HTML 代码进行标记化和树构建。
- 标记化是词法分析过程,将输入内容解析成多个标记,包括起始标记、结束标记、属性名称和属性值。
- 标记化生成器会识别标记,然后传递给树构造器,然后接受下一个字符,识别下一个标记,如此往复直至全部输入结束。如图:

- 至此,字符串被转换为标记。
- 解析算法结束,会将标记转换为节点(NODE),最后根据节点之间的联系生成 DOM 树。

- DOM 树生成完毕。下一步,是将 CSS 解析生成 CSSOM 树。 5.CSSOM 树转换过程和 DOM 类似,但与解析 DOM 不同的是,webkit 用的是 Flex 和 Bison 解析器生成器,通过 CSS 语法文件自动创建解析器,他会自下而上的进行解析,最后将 CSS 文件解析成 StyleSheet 对象,如图。

- 解析完成后,开始确定每个节点的样式,最终转化为 CSSOM 树,这一过程比较消耗资源,因为这一过程是递归 CSSOM 树的,并且建议书写 CSS 时减少使用关系型选择器。解析完成后生成如下 CSSOM 树。

- 解析的最后一步,生成渲染树,如图:

- 在构建 DOM 树的同时,浏览器就开始构建渲染树了。渲染树是由可视化元素按照其显示的顺序而组成的树,也是文档的可视化表示。
- 构建会按照正常的顺序执行,根据 display 的属性不同,对同一个节点创建对应类型的渲染器。
- 渲染树与 DOM 树是相对应的,但不一一对应,非可视化的元素不会插入渲染树中,例如 head 元素,以及 display 属性值为 none 的元素(visibility:hidden 会显示)。
Second - 布局与绘制
- 布局(Layout):前面提到的渲染树中并不包含节点的位置和大小信息,计算这些信息的过程称为布局(layout)。
- HTML 采用基于流的布局模型,只需要遍历一次就可以计算出所有的几何信息。布局按照从左至右,从上至下的顺序遍历文档。 布局是个递归的过程,它从根渲染器开始然后递归遍历所有子渲染器。每个渲染器都有一个“layout”方法,每个渲染器都会调用需要进行布局的子代的layout方法。
- 绘制(Painting):在绘制阶段,遍历渲染树,调用渲染器的 paint()方法在屏幕上显示其内容。渲染树的绘制工作是由浏览器的UI 后端组件完成的。
- 绘制顺序:绘制的顺序就是元素进入堆栈样式上下文的顺序,渲染器的堆栈顺序如下:
- background color
- background image
- border
- children
- outline
相关优化渲染 Tips: - 重绘(Repaint)与回流(Reflow)
重绘和回流会在我们设置节点样式时频繁出现,同时也会对性能产生一定影响。
- 重绘是当节点需要更改外观而不会影响布局的,比如改变 color,就是重绘。回流是布局或者几何属性需要改变就称为回流。
- 重绘不一定发生回流,回流一定会发生重绘。回流比重绘需要更多的成本,子节点进行回流会引起父节点一系列的回流。
- 当 DOM 结构越复杂时,需要重绘的元素也就越多。所以 dom 应该保持简单,特别是那些要做动画的,或者要监听 scroll/mousemove 事件的。
- 影响性能操作: 改变字体 添加或删除样式 定位或浮动(能用 transform 就不用定位和浮动)
Tips: 为什么操作 DOM 慢
这个问题比较基础,生成 DOM 是渲染引擎做的事,在代码中遇到 script 脚本就会启用** JS 引擎**,js 操作 DOM 就变成了两个引擎之间的协作与交互。操作 DOM 多了,就会进行线程之间的通信,消耗性能,造成页面卡顿.
Tips: 阻塞渲染
- 什么是阻塞渲染,渲染的前提是生成渲染树,所以在解析 HTML 和 CSS 的时候会阻塞渲染。如果想优化渲染,就尽量保持 DOM 扁平层级,并保持优化 CSS 选择器。
- 其次,解析器在遇到 script 标签时会立即执行脚本,这时停止解析 DOM,知道脚本执行完成,如果脚本是外部的就会加载外部资源,所以,首屏渲染不要加载 script,这也是将 script 标签放在 body 后面的原因。
- 现在多数都使用在 script 标签中加上 defer 和 async 属性。
- defer 属性表示 JS 文件会并行下载,脚本将在页面完成解析时执行,这时候可以把 script 标签放到任意位置。
- async 属性将 JS 文件标记为异步,脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)。
参考资料
- 高效前端:Web 高效编程与优化实践 —— 李银城
- How Browsers Work: Behind the scenes of modern web browsers:www.html5rocks.com/en/tutorial…
- developers.google.com/web/fundame…