前端性能优化
#积累/性能优化
性能指标
Performance关键时间点
- 首次绘制 (First Paint)
渲染进程确认要渲染当前的请求后,渲染进程会创建一个空白页面,创建空白页面的这个时间点称为FP。
FP 时间过久,说明HTML 文件可能由于网络原因导致加载时间过久 - 首次有效绘制 (First Content Paint)
然后,渲染进程继续请求关键资源,请求完关键资源之后才会执行进一步的绘制,当页面中绘制了第一个像素时,我们把这个时间点称为 FCP。 - 首屏时间 (Largest Content Paint)
接下来继续执行 JavaScript 脚本,当首屏内容完全绘制完成时,把这个时间点称为 LCP。
LCP时间过长,说明加载关键资源花的时间过久,也有可能是 JavaScript 执行过程中所花的时间过久 - DOMContentLoad事件
接下来 JavaScript 脚本执行结束,渲染进程判断该页面的 DOM 生成完毕,于是触发 DOMContentLoad 事件。 - onload事件
等所有资源都加载结束之后,再触发 onload 事件。
Audits/Lighthouse性能指标
- 首次绘制 (First Paint)
- 首次有效绘制 (First Meaningfull Paint)
- 首屏时间 (Speed Index),就是LCP
- 首次 CPU 空闲时间 (First CPU Idle)
也称为最小可交互时间First Interactive,表示页面达到最小化可交互的时间。要缩短首次 CPU 空闲时长,我们就需要尽可能快地加载完关键资源,尽可能快地渲染出来首屏内容。 - 完全可交互时间 (Time to Interactive)
简称TTI,表示页面中所有元素都达到了可交互的时长。所有的 JavaScript 事件已经注册完成,页面能够对用户的交互做出快速响应。缩短TTI,可以推迟执行一些和生成页面无关的 JavaScript 工作 - 最大估计输入延时 (Max Potential First Input Delay)
Web 页面在加载最繁忙的阶段, 窗口中响应用户输入所需的时间。缩短该延时,可以使用 WebWorker 来执行一些计算,从而释放主线程;或者重构 CSS 选择器,以确保它们执行较少的计算。
加载阶段
加载阶段的优化目标是:让页面更快地显示和响应。从指标上看,就是缩短首次绘制(FP)和首屏时间(LCP)之间的时间差。需用通过优化关键资源来实现。
能阻塞网页首次渲染的资源称为关键资源,关键资源会影响首屏时间和最小可交互时间。优化方向如下:
- 关键资源个数
优化:减少关键资源的个数
将 JavaScript 和 CSS 改成内联的形式;
JavaScript 代码没有 DOM 或者 CSSOM 的操作,则可以改成 async 或者 defer 属性,变为非关键资源;
::CSS如何变为非关键资源?:: - 关键资源大小
优化:
可以压缩 CSS 和 JavaScript 资源,移除 HTML、CSS、JavaScript 文件中一些注释内容 - 请求关键资源需要多少个 RTT(Round Trip Time)
TCP 协议传输一个文件时,由于 TCP 的特性,这个数据并不是一次传输到服务端的,而是需要拆分成一个个数据包来回多次进行传输的。RTT 就是单个数据包的往返时延,表示从发送端发送数据开始,到发送端收到来自接收端的确认,总共经历的时延。
通常 1 个 HTTP 的数据包在 14KB 左右,所以 1 个 0.1M 的页面就需要拆分成 8 个包来传输了,也就是说需要 8 个 RTT。
优化:
减少关键资源的个数和减少关键资源的大小搭配实现;
使用 CDN 来减少每次 RTT 时长
网络情况
下载概况
DOMContentLoaded时间:页面构建完成DOM所需要的时间,包括构建DOM所需要的HTML、JavaScript、CSS文件下载时间;
Load时间:浏览器加载完所有资源的时间,包括图片、样式表等。
单个资源时间线
- HTTP 请求的基础流程
发起一个 HTTP 请求之后,浏览器首先查找缓存,如果缓存没有命中,那么继续发起 DNS 请求获取 IP 地址,然后利用 IP 地址和服务器端建立 TCP 连接,再发送 HTTP 请求,等待服务器响应;不过,如果服务器响应头中包含了重定向的信息,那么整个流程就需要重新再走一遍。 - 时间描述
Queuing:请求排队时间。浏览器发起的请求不能立即执行,等待所需要的时间;
Stalled:停止时间。排队完成,发起链接之前,可能导致连接过程被推迟;
Proxy Negotiation:代理服务器连接协商所用的时间。请求使用了代理服务器所需要的协商时间;
Initial connection/SSL:和服务器建立连接所用的时间。包括TCP连接需要的时间,SSL 握手时间;
Request sent:和服务器建立连接之后,发送请求数据花费的时间;
Waiting (TTFB)第一字节时间:发送请求之后,到接收到服务器返回的第一个字节数据所用的时间。TTFB 是反映服务端响应速度的重要指标;
接收到第一个字节之后
Content Download:浏览器接收到第一个字节,到接收到全部响应数据所用的时间。
::对单资源的优化::
- Queuing时间过久
原因:排队时间过程,可能是是浏览器为每个域名最多维护6个连接。
优化措施:
一个站点的资源放在多个域名下;
站点升级到http2,去掉了每个域名最多维护6个连接的限制。 - TTFB时间过长
原因:服务器响应太慢
优化措施:
获取数据时间过长,增加缓存技术;
网络拖慢,则可以使用CDN来缓存静态文件;
请求头带了过多信息,减少不必要的cookie信息。 - Content Download时间过长
原因:文件过大
优化措施:减少文件大小,压缩或去除不必要的注释等。
交互阶段
交互阶段优化指的就是优化渲染帧的速度,决定了交互流畅度。
特点
- 交互阶段没有加载关键资源和构建DOM、CSSOM流程,通常就是由JavaScript触发交互动画;
- 交互导致布局信息修改,就会触发重排操作,触发后续一系列操作;
- 交互没有导致布局改变,则直接进入绘制阶段,触发重绘操作;
- 通过CSS 实现一些变形、渐变、动画等特效,不会触发重排或重绘,只会影响合成,而合成是非常快的。
优化
优化的一大原则是:让单个帧的生成速度变快。
- 减少 JavaScript 脚本执行时间,减少JavaScript执行霸占主线程影响渲染的时间。
1.将函数分解为多个任务,每个任务都不要太久;
2.采用Web Workers创建多个线程。Web Workers中没有DOM、CSSOM 环境,可以把一些和 DOM 操作无关且耗时的任务放到 Web Workers 中去执行。
- 避免强制同步布局
尽量不要在修改 DOM 结构时再去查询一些相关值。 - 合理利用 CSS 合成动画
合成动画是直接在合成线程上执行的,不会占用主线程,且执行高效。 - 避免频繁的垃圾回收
垃圾回收操作会占用主线程,尽量避免产生那些临时垃圾数据。
其他措施
::开发阶段::
- 用分析工具,例如webpack-bundle-analyzer,分析构建文件的组成;减少第三方库大小;
- 例如React中,减少render函数触发。
1.减少setState的使用,适当用私有属性代替state;
2.适当做组件拆分,减少组件渲染的节点;
3.shouldComponentUpdate生命周期中,深度比较props和state(耗性能),如果两个都没有变化则不做更新;使用Immutable.js来替代state和props数据结构,低成本做比较,减少组件树中的渲染节点
::构建阶段::
- 图片压缩处理
- 小图片转换为base64编码;
- 合理地切分代码,按需加载模块;
::部署阶段::
- nginx开启缓存,开启gzip功能;
- 图片使用cdn