URL从输入到页面展示

493 阅读6分钟

当我们打开一个网页,浏览器会将网页的内容呈现给我们,了解一个网页从请求开始到完全呈现的过程,可以让我们更好地开发高性能的网站

快速响应的网站提供更好的用户体验,等待资源加载时间和大部分情况下的浏览器单线程执行是影响Web性能的两大主要原因

请求阶段

当我们从浏览器的导航栏输入完URL后,浏览器会进行一系列的动作,去获取文档的内容

DNS解析

访问网站时,浏览器需要查找域名对应的IP

  1. 浏览器先查找本地hosts文件是否有对应的域名指向,如果有则直接获取对应的IP
  2. 如果本地没有配置,则查找本地是否有该域名的DNS缓存,如果有则取缓存中保存的IP(缓存只会在本地保留一段时间)
  3. 如果缓存中不存在,则请求本机配置的DNS服务器,获取域名IP

建立连接

查找到IP之后,浏览器通过TCP协议的“SYN-ACK/SYN-ACK”三次握手消息,尝试与服务器进行通信

http

TLS加密

如果我们使用的是https协议,除了通过三次握手建立连接之外,还需要进行TLS协商,建立加密连接

https

  1. 客户端向服务端请求数字证书
  2. 服务端将证书公钥传输给客户端
  3. 客户端验证证书的合法性,如果证书受信(或用户选择信任不受信的证书),浏览器会生成一串随机key,并用公钥加密后发送给服务端(非对称加密)
  4. 服务端接收到加密的key后,通过私钥解密获取key
  5. 服务端使用key加密传输内容(对称加密)发送给客户端,客户端通过key解密内容

请求响应

连接建立完毕后,开始传输数据,TCP链接通过拥塞控制算法(参考文章)。第一个响应包通常是14KB大小,客户端收到之后,下个包的大小会增加到之前包的2倍,直到达到设定的阈值或者遇到丢包。通过反复地探索网络传输能力来确定适合的传输速度,页面内容(只包含HTML内容)小于14KB对于web性能的优化来说是一个比较重要的点

解析阶段

浏览器收到第一块数据时,开始解析收到的内容,即使页面大于14KB,浏览器也会根据其要交给有的数据进行解析,所以在前14KB中包含浏览器所需的内容对于优化是很重要的。尽管接收到数据就开始解析,浏览器需要将HTML、CSS、JS全部解析完成,才能将页面展示到屏幕上

构建DOM树

dom

浏览器将HTML字符串转化为DOM数的过程大体上分为三步:

  1. HTML文本转化为token
  2. 将token转化为携带其属性及属性值的节点
  3. 将节点连接,组织成DOM树

良好的HTML文档格式,会提高构建DOM树的效率,节点数量越多,构建DOM的时间越长;

HTML解析的过程中,如果遇到非阻塞资源(图片、link、外联async/defer script等),会跳过等待,继续解析后面的HTML,但是需要注意以下几点:

  • link css虽然不阻塞HTML的解析,但是如果解析过程中遇到普通的(不带async/defer)script标签,因为js会阻塞HTML解析,而js有操作css的api,需要等待之前的css解析完毕
  • 添加defer属性的script不会阻塞HTML解析,会在HTML解析完成后执行js,执行完后浏览器会才会触发DOMContentLoaded事件
  • 添加async属性的script不会阻塞HTML解析,但是当js文件下载完成后,会立即执行js代码,如果HTML解析完成后,js文件未下载完成,浏览器会触发DOMContentLoaded,不会等待js下载

如果遇到阻塞资源(不带async/defer的script标签等),浏览器会暂停HTML的解析,优先去解析当前资源

预加载扫描器,浏览器在构建DOM树时,预加载扫描器会在后台检索资源,并根据优先级提前发起资源请求,当HTML解析到资源的位置时,可能资源已经开始下载,或者已经下载完成,减少了浏览器的阻塞

构建CSSOM树

cssom

CSSOM的构建和DOM类似,浏览器遍历css规则,将样式属性添加到每个关联的节点上,先从适用于节点的最通用规则开始,逐渐应用更具体的规则递归地优化计算样式

渲染阶段

当解析完HTML和CSS(构建完DOM和CSSOM)之后,浏览器开始进行页面的渲染,将之前构建的DOM和CSSOM进行合并,然后绘制到屏幕上

渲染树

render

DOM和CSSOM进行组合生成渲染树,渲染树会从DOM的根节点开始遍历,将对每个可见的节点(display属性不等于none)应用CSSOM上对应的样式规则,确定每个节点的计算样式

visibility:hidden的节点也会出现在渲染树上,虽然不会展示样式,但节点会占用页面空间

计算布局(Layout)

页面上多数节点都是一个盒模型,布局是确定渲染树中每个节点在页面中的宽高、位置的过程。

渲染树构建完成后,浏览器开始从根节点遍历,根据视区的大小和每个元素的盒模型属性,来确定元素的尺寸和位置,如果遇到不确定尺寸的元素(未定义宽高的图片),会为之提供占位符,当尺寸确定后重新计算

当对布局计算完成后,如果发生影响页面布局的动作,浏览器会重新计算节点大小、位置,此过程叫做回流(重排)

绘制(Paint)

当布局计算完成后,浏览器需要结合视区的尺寸以及页面的滚动,确定出页面中需要展示的元素,并将元素转化为实际的像素数据

  • 为了能够达到60fps的绘制效果,样式计算、布局计算、绘制这些过程需要在1000ms / 60 = 16.67ms内完成
  • 绘制过程是可以分层的,一些特定的元素(video、canvas、css属性包含3D变换/will-change/opacity的元素等),会将绘制过程提升到自己的层上,虽然提高了内存的管理成本,但是也提高了绘制性能

图层合并(Compositing)

分图层绘制完成之后,浏览器会将每个图层进行合成,如果页面发生变化,只重新绘制相应的图层,理想情况下,图层之间的绘制是不能互相影响的,可以减少重绘范围,但是如果发生了回流,会从Layout重新开始