浏览器的主要组件
要了解浏览器的工作原理,我们需要首先知道浏览器都有哪些主要组件:
- 用户页面:除了浏览器主窗口显示的请求页面外,其他显示的各个部分都属于用户页面
- 浏览器引擎:在用户界面和呈现引擎之间传送指令
- 呈现引擎:负责显示请求的内容
- 网络:用于网络调用
- 用户界面后端:用于绘制基本的窗口小部件
- JavaScript解析器:用于解析和执行JavaScript代码
- 数据存储:持久层
呈现引擎
主流程
- 解析:HTML解析和CSS解析
- 构建呈现树:整合DOM树与styleSheet
- 布局:为每一个节点分配坐标
- 绘制:遍历呈现树,由用户页面后端将每个节点绘制出来
解析
通过解析文档,可以得到一个代表文档结构的节点树,它也可以称为语法树。
如下如所示:
我们可以发现在图中存在一个翻译环节。在很多时候,解析树并不是最终的产品,解析也只是翻译过程中的一部分。我们希望通过翻译将输入的文档转化为另一种格式,这其中就需要借助解析树作为一个中间人的角色。
HTML解析
HTML的解析算法由两个阶段组成:标记化和树构建。
- 标记化:是一个词法分析过程,该算法输出结果是HTML标记,包括起始标记、结束标记、属性名称以及属性值。
- 树构建:由标记生成器生成的每个节点会发送到树构建器进行处理,这些元素不仅会被添加到DOM树中,也会添加到开放元素的堆栈中。
CSS解析
通过CSS解析会将CSS文件解析成stylesheet对象,且每个对象都包含CSS规则(选择器与声明)。
处理脚本和样式表的顺序:
解析器遇到script标记时会立即解析并执行脚本,此时文档的解析就会停止直到脚本执行完毕。如果脚本来自外部则停止解析过程,直到网络同步抓取资源完成后再继续。
通过预处理器,资源可以在并行连接上加载,从而提高整体速度。但是预处理器只解析外部资源引用。
Firefox 在样式表加载和解析的过程中,会禁止所有脚本。而对于 WebKit 而言,仅当脚本尝试访问的样式属性可能受尚未加载的样式表影响时,它才会禁止该脚本。
构建呈现树
呈现树是由可视化元素按照显示顺序而组成的树,也是文档的可视化表示,可以让浏览器按照正确的顺序绘制内容。
呈现树与DOM树的关系
- 呈现器和DOM元素是相对应的,但是非可视化的DOM元素不会插入在呈现树中。如果将一个元素的display值设置为none,则不会显示在呈现树中。
- 有一些 DOM 元素对应多个可视化对象。它们往往是具有复杂结构的元素,无法用单一的矩形来描述。
- 有一些呈现对象对应于 DOM 节点,但在树中所在的位置与 DOM 节点不同。浮动定位和绝对定位的元素就是这样,它们处于正常的流程之外,放置在树中的其他地方,并映射到真正的框架,而放在原位的是占位框架。
构建呈现树时,需要计算每一个呈现对象的可视化属性。每个DOM节点都有一个"attach"方法,在节点插入DOM树时会调用节点的attach方法,计算该节点的样式属性生成呈现器。下面让我们看一下整合(webkit的术语叫‘附加’)的过程:
布局
呈现器在创建完成并添加到呈现树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。
HTML 采用基于流的布局模型,这意味着大多数情况下只要一次遍历就能计算出几何信息。处于流中靠后位置元素通常不会影响靠前位置元素的几何特征,因此布局可以按从左至右、从上至下的顺序遍历文档。但是也有例外情况,比如 HTML 表格的计算就需要不止一次的遍历 。
坐标系是相对于根框架而建立的,使用的是上坐标和左坐标。
布局是一个递归的过程。它从根呈现器(对应于 HTML 文档的 <html>
元素)开始,然后递归遍历部分或所有的框架层次结构,为每一个需要计算的呈现器计算几何信息。
绘制
在绘制阶段,系统会遍历呈现树,并调用呈现器的“paint”方法,将呈现器的内容显示在屏幕上。绘制工作是使用用户界面基础组件完成的。
绘制顺序
- 背景颜色
- 背景图片
- 边框
- 子代
- 轮廓