前言、浏览器架构
Chrome主要使用多进程架构,各个进程互相独立,具有各自所负责的功能,若要互相通信则采用IPC机制进行通信。
1.浏览器主进程:主要负责主界面显示,用户交互,各个进程管理
2.网络进程:负责网络资源下载和与渲染进程进行资源传输
3.渲染进程:子资源的加载,页面解析
4.GPU进程:GPU渲染加速,能够针对css的一些属性进行性能优化,使用GPU进行绘制
5.插件进程:管理插件使用和执行
1、DNS解析
当我们输入域名例如:www.baidu.com的时候,浏览器会首先调用器本地的DNS客户端来解析这个域名,因为http协议的底层tcp/ip协议只能够识别到ip格式的地址,有了ip地址我们就能正确地识别到目标服务器并开始发送数据。
那么什么是DNS呢,它是域名系统(Domain Name System),负责将域名解析成ip地址,由根服务器,顶级服务器,二级服务器(权威DNS服务器)等组成,分层地逐步地将域名解析出来,那么接下来说下浏览器将域名解析成ip的过程。
浏览器会先查找本地的DNS缓存有没该域名记录,若要则返回,无则向系统缓存进行查找
若系统缓存有该域名的DNS记录,则返回,无则向本地的DNS服务器查找
本地的DNS可能是你搭建的dns服务或者路由器提供的服务,在本地的DNS服务器缓存进行查找,无则向上一层的本地DNS服务器发起查询
无本地dns服务器都没有改记录,则向互联网运营商DNS缓存进行查找
互联网运营商也无该记录的话则向域名系统服务器发起查询,由根域名服务器,.com顶级域名服务器,.baidu.com二级域名服务器来进行递归查询,通常到这里就有该dns记录并返回ip地址
注:DNS主要基于UDP传输层协议,一次UDP名字服务器交换可以短到两个包:一个查询包、一个响应包。一次TCP交换则至少包含9个包:三次握手初始化TCP会话、一个查询包、一个响应包以及四次分手的包交换。考虑到效率原因,TCP连接的开销大,故采用UDP作为DNS的运输层协议,这也将导致只有13个根域名服务器的结果。(UDP不能保证数据传输的可靠性,也无法避免接受到重复数据的情况)
2、HTTP连接
收到ip地址后就可以发送http请求了,http的请求报文包括状态行,请求头和请求消息报文,由传输层通过tcp/ip协议转化成数据包,经过网络层、链路层、物理层后再向上逐层递交和转化在应用层里返回给服务器,服务器取得数据处理后,发送响应报文包括状态行,响应头和响应消息报文,这样浏览器就获取到响应数据。
三次握手
http协议是基于tcp/ip协议,而在开始数据传输之前会先进行tcp的通道连接,通过3次握手来确定是否连接成功。
- 第一次握手:客户端发送SYN(synchronous建立联机)为1,seq(顺序号码)为随机数x,发送到服务端,要求建立连接
- 第二次握手:服务端接收SYN为1的建立连接请求,便向客户端发送确认请求,SYN为1,ACK(acknowledgement 确认)为1,seq为随机数y,ack(确认号码)为x+1
- 第三次握手:客户端接收到确认请求,便会校验ack是否为x+1,若正确则发送ACK为1,ack为y+1,至此tcp连接建立成功
四次挥手
数据传输完成后会通过四次挥手来结束连接。
- 第一次挥手:客户端向服务器发送FIN为1,seq为随机数x,表示已经没任何数据发送了
- 第二次挥手:服务端接收到客户端的FIN包,表示接收到客户端关闭连接的请求,但还没完全关闭,此时向客户端发送ACK为1,ack为x+1
- 第三次挥手:当服务端做好完全关闭连接的准备时,会再向客户端发送FIN为1,seq为随机数y
- 第四次挥手:客户端收到服务端结束关闭的请求后,向服务端发送ACK为1,ack为y+1,等待2MSL(2 Maximum Segment Lifetime),若再没收到服务端的响应,便结束连接,至此四次挥手连接关闭
3、页面渲染
构建DOM树
浏览器不能够直接识别到html的文件,它要首先将html文件转换成一种数据结构的类型-树,我们将这个生成后的类似树状结构数据称为DOM,每个元素表示DOM上的一个节点,浏览器遍历这些节点渲染成页面元素。
构建CSS STYLESHEETS
同样道理,浏览器会将css转换为一种浏览器可以理解的结构styleSheets,再与DOM树结合,构成了具有样式的布局树,对应节点上会有相应的样式。这里的布局树会去掉隐藏的节点,只有真实显示的节点
布局阶段
有了布局树就可以将元素渲染到页面上,样式的渲染遵循层叠继承规则,当我们需要修改样式的时候,这里面的布局涉及重排和重绘
回流(reflow)(重排)
页面重新渲染,重新布局,修改dom的宽高,位置会触发
重绘(repaint): 页面重新绘制,例如修改字体颜色,背景等
回流需要重新计算布局,耗费性能,而重绘只是局部更新,性能渲染较小。回流必定会触发重绘,而重绘不一定需要回流。
在操作DOM的时候,我们应该尽可能地减少回流和重绘,降低性能损耗
GUI渲染线程
接下来我们主要分析GUI渲染线程执行的详细过程:
1. 解析HTML文件,构建DOM树,同时浏览器主进程负责下载CSS文件
2. CSS文件下载完成,解析CSS文件成树形的数据结构,然后结合DOM树合并成RenderObject树
3. 布局RenderObject树,负责RenderObject树中的元素尺寸,位置等计算
4. 绘制RenderObject树,绘制页面的像素信息
5. 浏览器主进程将默认图层和复合图层交给GPU进程,GPU进程再将各个图层合成(composite),最后显示出页面
注:
- 默认图层指的就是处于普通文档流的元素;
- 复合图层一般指使用动画执行或者
<video><iframe><canvas><webgl>
等元素,也可以使用z-index将层级高的元素变成复合图层,使用复合图层可以进行硬件加速,其原理就是避免了默认图层的重绘和回流,想了解的童鞋可以自行深入研究。
了解GUI渲染线程的执行过程后,我们可以根据其渲染原理进行渲染优化:
- 尽可能提前引入css文件,例如在头部引入css文件;
- 尽可能早加载css文件中引用的资源,例如自定义字体文件,可以使用预加载,在link标签加入’rel=”preload” as=”font”‘该元素属性,不然会造成渲染阻塞
- 在DOM和CSS渲染之后加载js文件,例如在尾部加载js文件,或者使用该元素属性”defer”和”async”,进行js文件异步加载,但是在不同浏览器会有兼容性问题。