综述
之前使用ExtJS时遇到一个问题:为什么依次设置多个组件的可见性界面会卡顿?在了解HTML的dom操作相关内容的时候也好奇这个东西到底是怎么回事,然后尤其搞不懂CSS和Html分管样式和网页结构,这个东西是怎么实现的,是不是很复杂?
带着这些问题,看了一些文章,尤其是听说了Redraw和Reflow的概念之后,开始研究了dom的性能调优,最近看了一篇《how browser work》,觉得写得很详细,结合之前看的文章,解决了不少的困惑,写一篇对这个文章的读后总结,顺便记下来自己掌握的一些浏览器性能的知识。
浏览器的总体结构
浏览器主要部件包括:
- 用户界面:包括浏览器输入栏、前进、后退、主页等非网页展示区。
- 浏览器引擎:用户交互和呈现引擎之间的桥梁。
- 呈现引擎:实现dom和Css计算和渲染功能的部分,也是本文的主题。
- JS解释器。parse和执行JS代码。
- 数据存储,数据存储的持久层。
具体结构如下图所示:
Figure : Browser components
呈现引擎(rendering engine)
呈现引擎的工作就是呈现,包括呈现HTML/XML/pdf/image/CSS等等,当然我们主要关心呈现HTML+CSS这两个部分。
呈现引擎这个名字我们可能不熟,但是WebKit、Blink大家应该听过,Safari的呈现引擎就是Webkit,Chrome目前的呈现引擎是Blink,是Webkit的一个分支,另外Firefox也有自己的呈现引擎Gecko,IE的是Trident(本文写作的时候应该没有Edge)。本文介绍呈现引擎主要围绕Webkit和Trident来讲,会涉及到两者的异同,也就是Chrome、Safari和Firefox。
呈现引擎基本工作流程
如上图所示,呈现引擎从网络中收到资源文件后,首先Parse HTML文件,生成Dom树,然后开始parse外部和内部的CSS样式,生成CSS规则组,然后以Dom树为基础生成Render tree,render tree虽然没有渲染在页面上,但包含了足够的信息render出一个像素页面。因此调用render tree的layout方法开始根据dom tree结构,上面每个元素的display/width/height/minwidth/minheight/maxwidth/maxheight/border/padding/margin/position/float/left/right/top/bottom等layout相关的属性计算出对应元素的真实位置信息,在此基础上调用render tree的paint方法依据位置排布按特定顺序逐个绘制组件。
Webkit和firefox Gecko呈现引擎的工作流图
Figure : WebKit main flow
Figure : Mozilla's Gecko rendering engine main flow
可以看出总体流程大同小异,更多的是名词叫法的差异。
本文随后将按照上面的总体流程,分为parse(包括dom tree和style rules生成)、render tree(frame tree)、layout(reflow)&paint(draw)三个大章节介绍呈现引擎。
Parse: Dom tree and style rules
Parse术语浅析
对于一个操作,包括编程语言和方程、公式,作者首先以文本形式写成,但要计算机理解并执行,就需要按照一定语法写成,这样计算机才能根据一定的原则,把文本转化成结构化的操作树,然后再根据这些操作来执行命令,从文本转化为操作树的过程即Parse。
例如我输入了2+3-1这段文本,将会返回如下parse tree: