工作中我们需要解决各类卡顿、缓慢、白屏问题,优化产品用户体验。本篇会根据几种常见的场景,提供前端性能优化的思路和方案。
哪些环节可以性能优化?
大家知道,网页响应速度的快慢、用户交互是否丝滑是前端性能的主要考核点。在本系列第六篇中,有详细介绍用户访问网址到页面展示的过程。这里我们将这个过程分解,剖析其中潜在的优化点。
- 用户输入网址,DNS 会将网址中的域名解析为 IP 地址,以建立连接。在这个环节中,如何快速解析域名、建立物理距离尽可能短的连接,是性能优化的重点。
对于静态构建的前端项目,我们可以将文件部署到 CDN 服务器中,利用 CDN 就近服务、稳定传输的特点。快速建立稳定的文件传输通道。如果是服务端应用,同样可以参考 CDN 的机制,建立多个地区的服务器。
- 与服务器建立连接后,就开始传输页面资源,资源体积越小传输越快。我们要做的是打包出尽可能小的资源文件包括 js、css、图片等等
当前大部分项目都使用了构建工具如 webpack、vite。构建工具中的 按需加载、懒加载、tree shaking 等功能都能很好的帮助我们压缩 html、js、css 文件;对于图片资源我们可以考虑图片压缩、webp格式;我们还可以开启 gzip 来大大降低传输体积、开启缓存跳过传输过程。
- 通常前两步会占用比较多的时间,接收到资源文件后,浏览器会根据这些资源构建页面。大部分网页会需要再次请求服务端接口获取数据来渲染最终的页面。
此时我们应该了解浏览器对资源的解析过程,合理安排解析顺序来加快页面构建速度;还应该做好过渡动画、骨架屏,同时让服务端配合优化接口来提升页面渲染速度。
- 对前端同学来说还有一些特殊场景例如:小程序开发;APP、小程序中的 webview;同样我们可以通过减小打包体积、提前预加载页面来提升响应速度。
查看网页性能的方法
从上面的环节中可以看出,性能考核主要为两大步骤,一个是网络传输,一个是页面渲染和交互。
查看网络传输性能
网络传输主要通过 Chrome Dev Tool 中的 NetWork 选项卡查看。其中 overview 可以看到资源的加载时间线,即加载的开始时间和耗时;顶部工具栏可以勾选是否保留历史日志、是否禁用缓存、是否限制网速;中间的列表可以看到加载的文件名、响应状态码、大小、加载耗时;点击列表其中一条,可以看到这条请求的详细请求信息和返回内容。
通过加载顺序、大小、耗时,我们可以判断出页面资源加载的主要耗时点,例如 加载顺序不合理,资源没有并行加载; js 文件体积过大;图片文件体积过大;xhr 请求耗时过长等问题。将这些问题按优化性价比排列后再逐一解决。
查看页面渲染和交互性能的四种方法:
window.performance
主要用来查看页面渲染过程的关键时间节点,文档:MDN Performance API
- Chrome Dev Tool 中的 Performance 选项卡。在这个选项卡中,你可以录下一段时间的网页操作,查看这段时间中的 js 执行耗时、DOM 渲染耗时、界面绘制耗时、系统耗时。performance 官方文档(需翻墙)
- Chrome Dev Tool 中的 lighthouse 选项卡。这里会给出 页面性能、PWA、无障碍、最佳实践、SEO 五项的分数,还会给出对应的建议。lighthouse 官方文档(需翻墙)
- 在 js 代码中自行打印执行时间,例如在执行前记录当前时间戳,在执行结束后减去执行前时间戳。用来记录某个函数、某段代码的执行时间。
具体如何优化
上面我们粗略了解了一些优化方案,这里我们说说具体该如何实现。我会给每个方案按优化效果和实现难度打分(打分比较主观,仅供参考)、按推荐程度排序,大家在实践中可以先使用性价比高的方案,快速起到优化效果。
1. 启用 gzip 压缩
优化效果 ★★★★★、实现难度 ★
gzip 后文件体积一般能压缩到原来的 1/3,能大大提升网页加载速度,在 response header
中观察有 content-encoding: gzip
请求头则开启了 gzip。配置以 nginx 为例,添加 gzip 配置即可:
server {
#开启gzip
gzip on;
#低于1kb的资源不压缩
gzip_min_length 1k;
#压缩级别【1-9】,越大压缩率越高,同时消耗cpu资源也越多,建议设置在4左右。
gzip_comp_level 3;
#需要压缩哪些响应类型的资源,多个空格隔开。
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;
#配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_disable "MSIE [1-6]\.";
#是否添加“Vary: Accept-Encoding”响应头
gzip_vary on;
}
gzip 需要消耗一定的 CPU 资源,通常文本文件开启 gzip 收益是比较大的。图片等文件如果已经压缩过,可以根据压缩效果酌情开启。
2. 开启 HTTP 缓存
优化效果 ★★★★、实现难度 ★
HTTP 缓存对于二次加载的页面效果很好。如果打包出的 js、css 文件有哈希值,作为索引的 html 文件配置不缓存,而带哈希的文件可以设置长期缓存
location / {
## 以 htm|html 结尾的文件加上不缓存的请求头
if ($request_filename ~* .*\.(?:htm|html)$)
{
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}
root html;
index index.html index.htm;
}
3. 优化服务端接口响应速度
优化效果 ★★★★、实现难度 ★
这一块的实现难度其实是很高的,涉及 SQL 优化、负载均衡 等等,但因为通常不是我们前端同学开发,我们大可以把优化需求提给后端同学,帮助他们完成 KPI。
4. 启用 CDN 服务
优化效果 ★★★、实现难度 ★
如果你的服务器部署地点离常用用户不远,例如服务器在上海,用户主要是江浙沪,则提升不大。反之则应该使用 CDN 服务来部署页面资源以提高用户加载速度。
5. 图片使用 webp 格式
优化效果 ★★★★、实现难度 ★
首先我们检测浏览器是否支持 webp 图片,并注入全局变量 canUseWebp
let $img = new Image();
$img.onload = function () {
window.canUseWebp = true;
};
$img.onerror = function () {
window.canUseWebp = false;
};
$img.src =
"data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vlAAAA=";
然后准备好图片的 webp 地址和 png 地址,这两个地址的区别要有规律,方便编写公共方法
// 主要功能是拼好图片地址,怎么拼根据自身业务配置确定
getImgSrc(imgPath) {
const host = 'cdn 域名'
const imgType = window.canUseWebp ? 'webp' : 'png'
return `//${host}/${imgType}/${imgPath}`
}
6. 合理安排 HTML 中的标签顺序
优化效果 ★★、实现难度 ★
由于浏览器解析 HTML 文件是从上到下的,我们可以根据重要程度安排标签顺序,script 标签可以酌情加上 async
或 defer
属性。 async
属性,可能阻塞解析也可能不阻塞,而defer
属性一定不阻塞。
7. 在 APP 中预加载 webview
优化效果 ★★★★★、实现难度 ★★★
这块实现涉及 APP 方的配合,需要 APP 在不影响用户正常使用的时机,预初始化 webview。这样在用户点进页面时,webview 已经提前准备好,并且预载了公共资源文件如 vendor.js。可以很大提升 webview 在 APP 中的体验。
具体实现在 安卓、IOS 中各有不同:
8. webpack 代码分离、tree shaking
优化效果 ★★★★、实现难度 ★★
在 webpack 的配置中,我们可以使用 entry 配置、SplitChunksPlugin 来将代码分离成多个 chunk(官方文档:代码分离);可以使用import('xxxx');
来动态导入依赖
webpack 在构建中能够智能去除有引用但未使用到的无副作用代码,这个过程称为 tree shaking (官方文档),可以通过 package.json
的 sideEffects
属性标记无副作用的文件:
{
"name": "your-project",
"sideEffects": ["./src/some-side-effectful-file.js"]
}
配置好代码分离后,想看看打包效果及分析,可以使用 Webpack Bundle Analyzer 等工具来分析:
9. 开发页面过渡效果、骨架屏
优化效果 ★★★★、实现难度 ★★★
在一些确实需要用户等待的场景,我们可以通过其他方式缓和等待的过程,提升用户体验。例如文章加载过程中,展示灰色骨架屏
还有页面、列表等待过程中加上 “加载中..” 样式,按钮加上点触反馈等等方法
虽然无法直接缩短用户的等待时间,但是在等待中起到了缓和效果,同样能够提升用户体验和产品质感。
结语
可以看到,常用的性能优化方案在各大技术平台都多有实践,难度都不高,大家只要根据自身的项目情况,锁定方案照搬即可。