概览

浏览器是多进程多线程的

浏览器主要进程

  1. Browser进程:是浏览器的主进程,负责主控,协调,只有一个。
  2. renderer进程:又名浏览器内核,每个tab页面对应一个独立的renderer进程,内部有多个线程。
  3. GPU进程:负责3D绘制,只有当该页面使用了硬件加速才会使用它

Browser进程的主要任务

  1. 负责下载页面的网络文件
  2. 负责将renderer进程得到的存在内存中的位图渲染(显示)到页面上
  3. 负责创建和销毁tab进程(renderer进程)
  4. 负责与用户的交互

renderer进程

  1. 负责脚本执行(js引擎)
  2. 位图绘制
  3. 事件触发
  4. 任务队列轮询(事件循环)

renderer进程中的多线程

  1. js引擎线程
  2. GUI渲染线程
  3. 事件触发线程
  4. 定时触发线程
  5. 任务队列轮询线程
  6. http请求线程

js引擎线程:

也称js内核,解析js脚本,执行代码 - 与GUI线程互斥,即当js引擎线程运行时,GUI线程会被挂起,当js引擎线程结束运行时,才会继续运行GUI线程 - 由一个主线程和多个web worker线程组成,由于web worker是附属于主线程,无法操作dom等,所以js还是单线程语言(在主线程运行js代码)

GUI渲染线程:

用于解析html为DOM树,解析css为CSSOM树,布局layout,绘制paint - 当页面需要重排reflow,重绘repaint时,使用该线程 - 与js引擎线程互斥

事件触发线程:

当对应事件触发(不论是WebAPIs完成事件触发,还是页面交互事件触发)时,该线程会将事件对应的回调函数放入callback queue(任务队列)中,等待js引擎线程的处理

定时触发线程:

对应于setTimeout,setInterval API,由该线程来计时,当计时结束,将事件对应的回调函数放入任务队列中 - 当setTimeout的定时的时间小于4ms,一律按4ms来算

http请求线程:

每有一个http请求就开一个该线程 - 当检测到状态变更的话,就会产生一个状态变更事件,如果该状态变更事件对应有回调函数的话,则放入任务队列中

任务队列轮询线程:

用于轮询监听任务队列,以知道任务队列是否为空

GUI渲染线程

  1. html解析

html解析包含有一系列的步骤,过程为Bytes -> Characters -> Tokens -> Nodes -> DOM。最终将html解析为DOM树。

Conversion转换:浏览器将获得的HTML内容(Bytes)基于他的编码转换为单个字符
Tokenizing分词:浏览器按照HTML规范标准将这些字符转换为不同的标记token。每个token都有自己独特的含义以及规则集
Lexing词法分析:分词的结果是得到一堆的token,此时把他们转换为对象,这些对象分别定义他们的属性和规则
DOM构建:因为HTML标记定义的就是不同标签之间的关系,这个关系就像是一个树形结构一样。例如:body对象的父节点就是HTML对象,然后段略p对象的父节点就是body对象。
1
2
3
4
  1. css解析

与html解析类似,他解析最终形成CSSOM树,

过程为Bytes -> Characters -> Tokens -> Nodes -> CSSOM。

  1. render树

html解析和css解析是并行的,css的下载和解析不会影响DOM树,所以不会堵塞html文件的解析,但会堵塞页面渲染。

由DOM树与CSS树结合形成的渲染树(其中无法显示的元素,如script,head元素或diplay:none的元素,不会在渲染树中,也就最终不会被渲染出来),页面的布局,绘制都是以render树为依据。由以上的DOM树与CSSOM树,最终得到渲染树。

  1. 回流与重绘

这里还有两个概念:布局与绘制。

- 布局是页面首次加载时进行的操作,重新布局即为回流
- 绘制是页面首次加载时进行的操作,重新绘制即为重绘
- 当页面的某部分元素发生了尺寸、位置、隐藏发生了改变,页面进行回流。得对整个页面重新进行布局计算,将所有尺寸,位置受到影响的元素回流。
- 当页面的某部分元素的外观发生了改变,但尺寸、位置、隐藏没有改变,页面进行重绘。(同样,只重绘部分元素,而不是整个页面重绘)
1
2
3
4

回流的同时往往会伴随着重绘,重绘不一定导致回流。 所以回流导致的代价是大于重绘的。

触发回流:

页面初始化渲染
窗口的尺寸变化
元素的尺寸、位置、隐藏变化
DOM结构发生变化
修改字体大小
减少回流:
减少逐项更改样式,最好一次性更改style,或是将更改的样式定义在class中并一次性更新
避免循环操作DOM
将复杂的元素绝对定位或固定定位,使他脱离文档流,否则回流代价很高
1
2
3
4
5
6
7
8
9