浏览器进程
浏览器输入一个网址后的主流程![](https://i-blog.csdnimg.cn/blog_migrate/405d11aa814d07b76dc95049ab4c7751.png)
一、用户输入
根据以下规则,把用户输入的内容加上协议,合成为完整的 URL。
-
判断输入的关键字是搜索内容,还是请求的 URL
-
如果是搜索内容:使用浏览器默认的搜索引擎,来合成新的带搜索关键字的 URL。
-
如果是地址:添加协议头等信息
二、网络请求
浏览器进程通过IPC进程协议与网络进程通信,让网络进程开始请求:
检查缓存,如果有缓存则直接返回
浏览器发送请求前,根据请求头的expires
和cache-control
判断是否命中(包括是否过期)强缓存策略,如果命中,直接从缓存获取资源,并不会发送请求。如果没有命中,则进入下一步。
DNS解析,获取真实IP地址
TCP三次握手
第一次握手
客户端向服务端发送连接请求报文段。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端便进入 SYN-SENT 状态,x 表示客户端的数据通信初始序号。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入 SYN-RECEIVED 状态。
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功。
HTTPS握手(HTTPS协议需要)
-
客户端发送第一个随机值
client-random
,需要的协议和加密方式 -
服务端收到客户端的随机值,自己也产生第二个随机值
service-random
,并根据客户端需要的协议和加密方式来使用对应的方式,发送自己的证书(如果需要验证客户端证书需要说明) -
客户端收到服务端的证书并验证是否有效,验证通过会通过证书的公钥加密
client-random
+service-random
再生成第三个随机值pre-master
并发送给服务端。 -
服务端收到加密过的随机值
pre-master
,会使用私钥解密pre-master
获得3个随机值后,按照之前规定的加密方式,生成密钥master secret
并发送确认消息给浏览器。 -
这时候客户端也将拥有的三个随机值
client-random
、service-random
、pre-maste
,按照之前约定的加密方式生成密钥master secret
,接下来的通信就可以通过该密钥来加密解密
构建与响应请求
发送请求
响应请求
三、渲染页面
准备渲染进程
新增渲染进程(默认策略)
从一个页面点击打开了另一个非同源新页面或者直接网站输入打开新标签页面;比如打开QQ页面,因为直接新增新标签页面,新增渲染进程
再从该页面点击新开标签新闻页,因为新增了不同源标签页(new.qq.com),所以新增渲染进程
复用渲染进程
从一个页面内点击打开了另一个同源新页面;
比如从一个网站点击打开一个新标签页,该标签页同站,所以复用了进程。
比如从新闻页面国际栏目点击进入军事栏目,没有新增标签页,也是同站,所以复用进程。
同源策略如下:
提交文档
浏览器需要进行提交文档的流程,所以输入地址后,之前页面是加载一会才更新为新页面,具体流程如下:
- 建立传输管道:渲染进程接收到浏览器发出的 “提交文档” 消息后,会和网络进程建立传输数据的 “管道”;
- 确认提交:等数据传输完成后,渲染进程会返回 “确认提交” 的消息给浏览器进程;
- 更新浏览器界面状态:浏览器进程收到确认提交消息后,更新界面状态,包括安全状态、地址栏的URL、前进后台的历史状态以及进入渲染页面阶段
渲染阶段(浏览器核心中的核心)
构建DOM树(主线程)
分为四个阶段:
1. 输入HTML文件;
2. 字节流转换为Token:分为 Tag Token 和文本 Token。对应我们的起始标签、终止标签、和文本内容。
3. HTML解析器解析
4. 转换输出为document
样式计算,生成样式树styleSheets(主线程)
1. 首先将 CSS 样式转换为 document
里的 styleSheets,优先级——元素style
> <style>标签内CSS
> <link>引用的CSS文件。
与 DOM 转换为 TOKEN,
styleSheets
才是浏览器能理解的数据结构。
2. 属性值标准化
3. 进行样式计算,基于继承规则和层叠规则,确定样式优先级,为每个 DOM 生成一个 Computed
的样式。
继承规则:每一个节点都可能包含父节点的样式——假设继承了父属性
a
,若对应一个dom有同一个属性,记b,
如果b
的优先级大于a
那样式就采用b
。
层叠规则:定义了如何合并来自多个源的属性值的算法
布局阶段,生成布局树(主线程)
计算每一个 DOM 节点的位置信息,然后保存在布局树中:
1. 遍历DOM树所有可见节点,会忽略不可见节点,比如head标签、display:none的元素等;
2. 结合 computeStyle 进行布局计算, 创建布局树。
图层构建,生成图层树(主线程)
为了方便局部渲染,浏览器会根据布局数把展示的元素进行分层。
不是布局树的每个节点都包含一个图层,节点若没有对应的层则从属于父节点的图层。
而节点是否创建新图层的条件包括层叠上下文属性——position: fixed,z-index,filter,opacity 以及文字过多需要剪裁。
可以在 chrome DevTools 的 Layers 查看分层信息:
图层绘制阶段,生成绘制列表(主线程)
简单来说,图层绘制阶段就是生成由一系列绘制指令构成的指令表,提交给合成线程。流程如下:
点击单个图层,可以查看到绘制指令:
分块(合成线程)
因为图层大小可能远大于视口的大小,所以合成线程会把土城分割层图块。
栅格化,生成位图(合成线程)
栅格化简单来说就是将图块转换成位图(浏览器渲染进程能理解的01集合),合成线程会按照视口附近的图块来优先生成位图。具体流程是:
-
每一个图块调用栅格化线程;
-
栅格化线程将图块绘制指令提交给GPU进程去生成位图,并保存在GPU内存中。
合成与显示(非主线程)
这是浏览器交接给用户的最终阶段:
1. 发送绘制命令:栅格化结束后,发送绘制图块命令--DrawQuad;
2. 合成绘制命令:由 viz 组件合成所有栅格线程的绘制命令;
3. 绘制:将页面内容绘制到内存中,然后将内存显示到屏幕上。
总结
-
渲染进程将 HTML 内容转换为能够读懂的DOM 树结构。
-
渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式,形成ComputedStyle。
-
创建布局树,将元素的布局信息的信息保存在树中。
-
对布局树进行分层,并生成图层树。
-
为每个图层生成绘制列表,并将其提交到合成线程。
-
合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
-
合成线程发送绘制图块命令DrawQuad给浏览器进程。
-
浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上