Description
浏览器理解
浏览器组成
- User Interface(用户界面),浏览器除请求的页面之外的其他部分
- Browser engine(浏览器引擎),在用户界面和呈现引擎之间传送指令
- Rendering engine(呈现引擎),负责显示请求的内容
- Networking(网络),用于网络请求
- UI Backend(用户界面后端),用于绘制基本的窗口小部件,比如组合框和窗口。公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法
- JavaScript Interpreter(JavaScript 解释器),解析和执行JavaScript代码
- Data Persistence(数据存储),持久层
整体结构如下图:
Rendering engine
渲染引擎从网络中获取文档内容,然后执行下列步骤
注意点:这是一个渐进的过程,浏览器不会等到整个HTML解析完毕,就会开始进行上述工作
一、解析
解析是将文档转化成有意义的结构,解析得到的结果通常是代表了文档结构的节点树,称作解析树或者语法树
解析的过程可以分为两个子过程:词法分析和语法分析
- 词法分析是将输入内容分割成大量标记的过程,该过程由词法分析器负责
- 语法分析是应用语言的语法规则的过程,该过程由解析器负责。根据语言的语法规则分析文档的结构,从而构建解析树
解析流程:
二、解析器类型
有两种基本类型的解析器:自上而下解析器和自下而上解析器
三、DOM与DOM树
<html>
<body>
<p>
Hello
</p>
<div>
<img src=""/>
</div>
</body>
</html>
当前文档将被翻译成如下的DOM树
四、脚本处理
正常情况下,脚本解析是同步的,当解析器遇到<script>标签时,会停止当前解析并立即执行脚本,如果脚本来自外部,则会先下载脚本。
defer 标注可以让解析器不停止解析文档,同时也会异步加载JS脚本,但是要等文档解析完成后再执行JS脚本
async 标注可以让解析器不停止解析文档,异步加载JS脚本,在JS脚本加载完成后停止解析并执行JS脚本
五、样式表
样式表的加载不会阻塞DOM树的解析
样式表的加载会阻塞DOM树的渲染
样式表的加载会阻塞后面JS语句的执行
六、Rendering Tree 和 DOM Tree的关系
Rendering Tree和DOM 元素相对应,但并非一一对应。非可视化的DOM元素不会插入(head, display:none)
也有一个DOM元素对应多个可视化对象(select,input换行)
七、样式计算
难点:
- 样式数据是一个庞大的结构,存储了无数的样式信息,可能造成内存问题
- 为每一个元素查找匹配的规则会造成性能问题
- 层叠规则复杂
布局
呈现器在创建完成并添加到呈现树时,并不包含位置和大小信息。计算这些值的过程称为布局或者重排
布局是一个递归的过程
根呈现器的位置左边是0,0,其尺寸为视口(也就是浏览器窗口的可见区域)
一、Dirty位系统
为避免对所有细小更改都进行整体布局,浏览器采用一直"dirty"位系统。如果某个呈现器发生了变更,或者将其自身或者子代标注为"dirty",则需要进行布局
二、全局布局和增量布局
全局布局的原因:
- 全局样式更改,例如字体大小
- 屏幕大小调整
其他布局采用增量布局的方式
三、同步布局和异步布局
-
增量布局异步执行
-
请求样式信息(如offsetHeight)的脚本可同步触发增量布局
-
全局布局往往是同步触发
四、换行
如果呈现器在布局过程中需要换行,会立即停止布局,并告知其父代需要换行。父代会创建额外的呈现器,并对其调用布局。
绘制
在绘制阶段,系统会遍历呈现树,调用"paint"方法,将内容显示在屏幕上。绘制工作是使用用户界面基础组件完成的。
程序引擎的线程
程序引擎采用单线程。
网络操作可以由多个并行线程执行。