前端性能对用户体验至关重要,讲解性能优化的文章也很多,本文将介绍基本的原则和方法。
原则
性能优化的首要原则是,优先解决妨碍用户体验的问题。
通过使用工具对性能问题进行度量,确认问题所在并获取到可度量的数据,设计优化方案,执行优化方案后对考察的指标进行比对,最终确认验证是否生效。
什么最优先
用户打开一个网站,首屏多快速度加载出来,多长时间可以进行交互,对用户是否流失极为关键。
因此我们组最优先的目标是,让首屏最重要的内容尽快可视、可交互。
对应的指标
统计性能的指标有很多,其中最重要的有FMP(是否有内容可视)和 TII(是否可以交互)。
但因为FMP中M代表meaningful,通常需要自己去推算,在Chrome中已经使用LMP(最大的可视化的内容)替代。
如何统计
很多在线网站提供了统计数据,但此种数据成为实验室数据,我们通常期望收集到的真实用户的数据。
W3C 2012年制定的Navigation Timing标准,让我们可以在主流浏览器使用performance API获取各阶段的时间。
探查LCP
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry);
}
});
observer.observe({entryTypes: ['largest-contentful-paint', 'longtask']});
使用上述代码可以对LCP进行侦听,但是注意:在网页加载的不同阶段,最大的Content是会变的,因此可能输出多个entry的值。
针对LCP优化的目标尽可能减少LCP的时间。
结合数据上报,我们可以看到上面什么时间点,什么元素在页面已经是可视状态。
探查TTI
TTI在API层面并不支持,可以使用Chrome提供的tti-polyfill,在安装后,就可以在代码中使用如下代码来输出TTI:
import ttiPolyfill from 'tti-polyfill';
ttiPolyfill.getFirstConsistentlyInteractive().then((tti) => {
console.log(tti);
});
针对TTI的优化目标是尽可能让它靠近LCP的值。
单个数据无意义
LCP和TTI的结果,通常会在不同用户、设备、时间上有不同的表现,单个数据值并不具备统计意义。
最好的做法是,结合数据上报,最终得到大量用户的数据,然后取中值。
在手机App上的秒开率,也是这么个思路,即1秒内内容交互的用户的占比。
关键渲染路径
CRP(关键渲染路径) 简单来说就是浏览器将HTML、CSS和JavaScript转化为可见的像素的过程。
有一个标准常被用来衡量CRP(关键渲染路径)的性能:
指标名 | 含义 |
---|---|
CRP resourcs | 请求资源的数量 |
CRP KB | 请求资源的大小 |
CRP length | 代表了从请求从客户端到服务端来回的次数(仅会阻塞渲染的资源) |
客户端的优化策略
理解加载渲染过程
JS阻塞DOM解析,CSS阻塞样式的渲染,我们的目标是尽可能早地渲染render tree的内容。
浏览器会同时发起多个连接去加载CSS和资源,我们希望尽早看到界面样式,因此CSS加载应该放在头部,希望JS代码不要阻塞DOM的解析,因此通常将JS的引入在body标签结束之前的位置。
减少请求资源的数量
我们可以用如下手段来减少请求资源的数量:
- 在
上使用defer/async
- 在
link
上使用媒体查询 - 使用内联的
CSS
、使用内联base64
图片 - 使用浏览器的强缓存
减小请求资源的大小
通过压缩、合并、混淆,都可以减少资源大小。
在Webepack使用了common trunk来提取公共代码、使用tree shaking将无用代码进行了剔除。
减少阻塞请求的来回次数
对于类似站点统计代码,并不需要阻塞网页加载,因此可以使用 async/defer。
字体文件、Sprite等方式都是将多个请求合并到了一个请求。
SSR则是将所需要的资源都打包到了一个HTML文件中,实现一步到位。
服务端/网络的优化
前节只是介绍了偏客户端优化的策略,我们还可以通过
- CDN来优化加载资源的物理路径,从而实现更快的加载
- 服务端进行资源缓存,协商缓存的策略减少数据库的查询
- 服务端采用GZIP压缩,减少传输资源的大小
- 将请求升级到HTTP2,HTTP2诞生的初衷就是为了提高传输效率低的问题
关于缓存,是网站性能优化的利器,需要浏览器和服务器配合决定,什么资源采取什么样的缓存策略。
比如,作为入口的HTML文件是禁止使用缓存的,每次都发请求到服务器。而对于其他资源,则使用Cache-Control做很长时间(比如1年)的缓存时间,每次变化后Webpack打包出来的资源都有的指纹并更新对应的HTML,也就确保每次访问的都是最新的资源。
下一步是什么
交互流畅
在用户能够很快打开网站以后,下一步就是如何让用户的交互过程尽可能流畅。
操作延时、动画卡顿 或 电脑开始轰鸣响起,通常说明发生了内存泄漏 或 执行了内存开销很大的任务。
前述performance API也有long task
类型的可以对长任务进行侦听。
因此下一步是学习如何基于Chrome的Performance进行调试,并解决妨碍流畅的问题。
还需要学习什么代码将会导致内存泄漏、怎么书写能减少“重排”和“重绘”的频率。
这一切都离不开对开发工具的熟练使用 和 实践。
希望后续,自己还可以继续补充一些更具实际操作的做法。