一、页面加载流程
用户在浏览器地址栏输入 URL 并回车后,浏览器会向 DNS 服务器发起 DNS 查询获取 IP 地址,并与服务器建立 TCP 连接。
在建立连接后,浏览器就可以发起 HTTP 请求。服务端接收到请求后,对请求进行响应,浏览器从响应结果中拿到数据,并进行解析和渲染。
最后在用户面前就出现了一个网页。
按照流程可以分为以下三个阶段:
1. 客户端发起请求阶段
客户端发起请求阶段是指用户在浏览器输入 URL 经过本地缓存确认是否已经存在这个网站。
如果没有,接着会由 DNS 查询从域名服务器获取这个 IP 地址,客户端通过 TCP 的三次握手和 TLS 协商向服务器发起 HTTP 请求建立连接的过程。
本阶段的用户等待时间 = DNS 查询时间 + TCP 三次握手及 TLS 协商时间 + 服务器数据响应时间
此阶段的前端瓶颈分为:本地缓存、 DNS 域名解析、HTTP 请求
1.1 本地缓存
本地缓存可以让静态资源加载更快,当客户端发起一个请求时,静态资源可以直接从客户端中获取,不需要再向服务器请求。
本地缓存分为强缓存和协商缓存。
- 强缓存:浏览器在加载资源时,根据请求头的 expires 和 cache-control 判断是否命中客户端缓存
- 协商缓存:浏览器会先发送一个请求到服务器,通过 last-modified 和 etag 验证资源是否命中客户端缓存
1.2 DNS 域名解析
每进行一次 DNS 查询都要经历从手机到移动信号塔,再到认证 DNS 服务器的过程,针对此问题可以采用DNS 缓存。
在打开浏览器或者 WebView 的同时通过浏览器提供的 DNS 预获取的接口进行配置。
1.3 HTTP 请求
请求阻塞就是浏览器为保证访问速度会默认对同一域下的资源保持一定的连接数,请求过多就会进行阻塞。
针对此问题可以采用以下方式优化:
- 域名规划
- 域名散列:通过不同的域名,增加请求并行连接数
2. 服务端数据处理请求阶段
服务端数据处理阶段是指 WebServer 接收到请求后从数据存储层取到数据,再返回给前端的过程。
此阶段的瓶颈点:数据缓存处理、Gip压缩、重定向
2.1 Gip压缩
Gzip 压缩是一种压缩技术,通过 Gzip 压缩后资源的下载速度会快很多,能大大提升页面的展示速度。
2.2 数据缓存
每请求一次数据接口,需要从客户端到后端服务器,再到更后端的数据存储层,一层一层返回数据,最后再给到客户端,耗时很长。
针对数据存储优化方案有以下:
-
Service Worker:浏览器的一个高级属性,本质上是一个请求代理层。它存在的目的就是拦截和处理网络数据请求
-
借助本次存储的接口缓存:在一些对数据时效性要求不高的页面,第一次请求到数据后,程序将数据存储到本地存储,下一次请求的时候,先去缓存里面取数据,如果没有缓存的话,再向服务器发起请求
-
CDN:通过在网络各处放置节点服务器,构造一个智能虚拟网络。将用户的请求导向离用户最近的服务节点上
2.3 重定向
重定向是指网站资源迁移到其它位置后,用户访问站点时程序自动将用户请求从一个页面转移到另外一个页面的过程。
重定向场景:
- 服务端发挥的302重定向
- META 标签实现的重定向
- 前端 Javasript 通过 window.location 实现的重定向
重定向危害:
- 产生新的 DNS 查询
- 产生新的 TCP 三次握手和 TLS 协商
- 产生新的 HTTP 请求
3. 客户端页面解析及渲染阶段
客户端解析:HTML解析器把页面内容转换为 DOM 树和 CSSOM 树的过程。
DOM 树全称为 Document Object Model 即文档对象模型,它描述了标签之间的的层次和结构。
CSSOM树,即 CSS 对象模型,主要描述样式集的层次和结构。CSS 解析器遍历其中每个规则,将CSS 规则解析浏览器可解析和处理的样式集合,最终结合浏览器里面的默认样式汇总形成具有父子关系的 CSSOM 树。
客户端渲染:主线程会计算 DOM 节点的最终样式,生成布局树,布局树会记录参与页面布局的节点和样式。
客户端绘制:把各个节点绘制到屏幕上的过程,绘制结果以层的方式保存。当文档中各个部分以不同的层绘制时,相互重叠时,就必须进行合成。
解析和渲染阶段流程环节多,逻辑复杂,瓶颈点也多比如,DOM树构建过程,CSSOM树生成阶段,重排和重绘过程等。
3.1 构建 DOM 树
-
非语义化标签:当 HTML 标签不满足 WEB 语义化时,浏览器就需要更多时间去解析 DOM 标签的含义。浏览器会进行语法纠错,这就会导致页面总的解析和渲染阶段需要更长的时间,严重影响页面展示性能
-
DOM 节点的数量多:构建 DOM 树的时间就会变长进而延长解析时间,拖慢页面展示速度
-
<SCRIPT>标签:无论是 DOM 或者CSSOM都可以被JavaScript所访问并修改,所以一旦在页面解析时遇到<SCRIPT>标签,DOM的构造过程就会暂停,等待服务器请求脚本
3.2 其他
- 浏览器渲染阶段的回流重绘
- 偏硬件领域的 GPU 绘图、操作作系统 GUI 和 LCD 显示等
- 网络层和服务层的拥塞预防、负载均衡和启动
- 页面解析和渲染的算法,如解析算法、标记化算法和树构建算法等
二、制定优化目标
1. 正推
2. 反推
结合正反推制定客观的优化目标,并把目标量化。
三、数据采集
1. 首屏时间
1.1 服务端模版业务
当页面中的 HTML 元素被加载和解析完成,DOMContentloaded事件触发。
首屏时间 = domContentLoadedEventEnd - fetchStart
1.2 单页面应用业务
MutationObserver 接囗提供了监视对 DOM 树所做更改的能力,它被设计为旧的 Mutation Events 功能的替代品。该功能是 DOM3 Events 规范的一部分。
在用户进入页面时,使用 MutationObserver 监控 DOM 元素,当 DOM 元素发生变化时,程序会标记变化的元素,记录时间点和分数并存储到数组中。
递归遍历 DOM 元素及其子元素,根据子元素所在层数设定元素权重。
比如第一层元素权重是 1,当它被渲染时得1分,每增加一层权重增加 0.5,第五层元素权重是 3.5,渲染时给出对应分数。(越往内层越接近真实的首屏内容如图片和文字,越往外层越接近 body 等框架层)
根据前面的得分,计算元素的分数变化率,获取变化率最大点对应的分数,然后找到该分数对应的时间,即为首屏时间。
2. 白屏时间
白屏时间即用户点击一个链接或打开浏览器输入 URL 地址后,从屏幕空白到显示第一个画面的时间。
白屏时间 = 页面开始展示时间domLoading - 开始请求时间navigationstart
3. 卡顿时间
在浏览器不支持 requestAnimationFrame 时利用 setTimeout 来模拟实现,在 fps_loop 里面完成 FPS 的计算。
不卡顿指标:连续 3 帧不低于 20 FPS,且保持恒定