当我们疲于开发一个接一个的需求时,很容易忘记去关注网站的性能,到了某一个节点,猛地发现,随着越来越多代码的堆积,网站变得越来越慢。
本文就是从这样的一个背景出发,着手优化网站的前端性能,并总结出一套开发习惯,让我们在日常开发时,也保持高性能,而不是又一次回过头来优化性能。
先来看看优化的成果,Lighthouse 的 Performance 评分合计提升 279%:
指标名称 | 优化前 | 优化后 | 提升 |
---|---|---|---|
Lighthouse Performance 评分 | 29 | 81 | 279% |
FCP(First Contentful Paint 首次内容绘制) | 0.7s | 0.7s | |
LCP(Largest Contentful Paint 最大内容绘制) | 6.2s | 2.5s | 248% |
TTI(Time to Interactive 可交互时间) | 10.1s | 2.1s | 480% |
Speed Index(速度指数) | 5.6s | 1.8 | 311% |
TBT(Total Blocking Time 总阻塞时间) | 820ms | 120ms | 683% |
优化前后对比:
优化前后对比接下来就是介绍下优化前我们要做哪些事件:
一开始我们只是感受到网站的页面打开时白屏时间较长,感觉性能是比较差的,那么具体有哪些性能指标需要去关注呢?
这里我使用的是 Chrome devtools 内置的 Lighthouse[1],Lighthouse 是一种开源的自动化工具,用于提高 Web 应用程序的质量。
Lighthouse 会在一系列的测试下运行网页,比如不同尺寸的设备和不同的网络速度。它还会检查页面对辅助功能指南的一致性,例如颜色对比度和 ARIA 最佳实践。
打开 Chrome devtools Lighthouse 即可使用。
在比较短的时间内,Lighthouse 可以给出这样一份报告。
这份报告从 5 个方面来分析页面:性能、辅助功能、最佳实践、搜索引擎优化和 PWA。像性能方面,会给出一些常见的耗时统计。
优化前Performance 评分统计,包括了以下指标:
FCP 测量在用户导航到页面后浏览器呈现第一段 DOM 内容所花费的时间。页面上的图像、非白色<canvas>
元素和 SVG 被视为 DOM 内容;不包括 iframe 内的任何内容。
LCP 测量视口中最大的内容元素何时呈现到屏幕上。这近似于页面的主要内容对用户可见的时间。
需要注意的是 LCP 的计算是一个动态的过程,如下图最后的图片才是这个页面中的最大内容绘制的元素。
lcpTTI 测量页面完全交互所需的时间。
TTI 是如何计算的呢,如下图首先沿时间轴正向搜索时长至少为 5 秒的安静窗口(安静窗口是指没有长任务且不超过两个正在处理的网络 get 请求),然后沿时间轴反向搜索安静窗口之前的最后一个长任务,如果没有找到长任务,则在 FCP 步骤停止执行,TTI 就是安静窗口之前最后一个长任务的结束时间,如果没有找到长任务的话,则与 FCP 值相同。
TTISpeed Index 衡量页面加载期间内容以视觉方式显示的速度。Lighthouse 首先捕获浏览器中页面加载的视频,并计算帧之间的视觉进度。
TBT 测量页面被阻止响应用户输入(例如鼠标点击、屏幕点击或键盘按下)的总时间。
通过添加 First Contentful Paint 和 Time to Interactive 之间所有长任务的阻塞部分来计算总和。任何执行时间超过 50 毫秒的任务都是长任务。
50 毫秒后的时间量是阻塞部分。例如,如果 Lighthouse 检测到一个 70 毫秒长的任务,则阻塞部分将为 20 毫秒。
如下图淡红色区域的时间总和就是这个页面的 TBT 分数。
TBT用于检测 Web 应用程序整体代码健康状况,包括是否包含文档类型、图片宽高比是否正确等等。
用于检测搜索引擎对网页内容的理解程度。
了解了关键的性能指标后,就可以测量看看当前网站的性能了,
上面看到综合评分是非常低的,Lighthouse 给出了应该从哪些地方开始优化的建议。
性能优化建议主要包括以下几点:
Lighthouse 诊断出的网站存在的问题:
{passive: true})
,导致需要等待侦听器完成执行后再滚动页面;
最佳实践方面有以下问题:
SEO 有以下问题:
根据上面 Lighthouse 报告,捋一捋项目中影响性能最大的因素,包括以下几点:
检查是否还有压缩空间,或者有无工具库未压缩的。
通过 webpack-bundle-analyzer 插件分析包体积,将一些大的 npm 包和 runtimeChunk 独立分包,减小包体积。
React.lazy + Suspense 封装懒加载组件,路由级组件引入懒加载组件。同时使用骨架屏作为懒加载的兜底组件,可以让用户感知加载更快。在鼠标移入导航栏时预加载路由组件,可以加快页面展示。
通过 import('xx').then(xx) 按需加载工具库。
项目内有一些 json 文件存储的静态数据,这部分文件上传至 CDN,改为 fetch 的方式按需引入。
检查项目中引入的 mf、npm 资源,将没有使用到的删除。
发现业务组件库通过 npm 引入的原子组件库,而项目本身又是通过 mf 引入的原子组件库,相对于引入了 2 遍原子组件库。
这时就需要改造业务组件库,也改成用 mf 的方法引入。
因为 webpack 的按需加载是通过 import、export 来标记的,因此想要一个好的按需加载的效果,就需要避免依赖嵌套的问题。
原子组件库 mf 暴露的方式会导致只用了 1 个 icon,就会加载组件库下所有 icon 对应的 chunk,导致资源浪费。
新建一个 icon 的 npm 包用于 icon 的按需引入。
通过以上优化手段,体积从 11.7mb 降低至 1.1mb,降低 10.6 倍。
优化前:
优化前优化后:
优化后对非首屏的图片采用图片懒加载策略。
使用图片时,设置图片的合理尺寸。
优先使用 webp 格式图片。
优化项目内的图片分辨率。
详细的 meta description、keywords 可以加快 SEO。
<meta name="keywords" content="xx" /> <meta name="description" content="xx" />
<img src="smiley.gif" alt="Smiley face" />
再来回顾下前后对比:
优化前,明显的感知白屏时间长:
优化前优化后,在清缓存的情况下也能实现秒开:
优化后整体性能提升 270%:
优化前后对比为了在后续的迭代过程中,保持高性能,引入内部前端监控平台 - 烛龙[2],可视化的监控前端性能。
第一步,加载 cdn 插件:
<script
defer
src="https://h5static.m.jd.com/act/jd-jssdk/latest/jd-jssdk.min.js"
></script>
第二步,在入口文件中,初始化 cdn 插件:
useEffect(() => {
// 初始化测速组件,在这里可以打开一些控制的开关,如是否上报接口
if (IS_PROD) {
// @ts-ignore
jmfe.profilerInit({
flag: xxx, // 这是应用ID,需要先在烛龙申请应用
autoReport: true,
autoAddStaticReport: true,
autoAddApiReport: true,
autoAddImageReport: false, // 支持所有图片上报,如果图片多,切记关闭,否则存在性能问题
performanceReportTime: 8000,
profilingRate: 1,
})
}
}, [])
第三步,查看监控数据:
在烛龙平台,小工具性能评分达 96分:
查看监控数据第四步,新增告警,实时监控:
烛龙平台支持多维度的告警服务,增加性能指标相关的告警,在性能异动时,及时发现问题,优化性能。
新增告警本文详细介绍了一个前端项目优化的详细过程,从优化前的问题分析,到具体的优化措施,最终实现了前端性能提升了近 3 倍。同时也将性能指标落到监控平台,实现可视化的监控前端性能指标。
希望能对你有所帮助,感谢阅读~
Lighthouse: https://developer.chrome.com/docs/lighthouse/
[2]烛龙: http://dra.jd.com/
[3]被删的前端游乐场-前端性能优化-归纳篇: https://godbasin.github.io/front-end-playground/front-end-basic/performance/front-end-performance-optimization.html#%E6%97%B6%E9%97%B4%E8%A7%92%E5%BA%A6%E4%BC%98%E5%8C%96-%E5%87%8F%E5%B0%91%E8%80%97%E6%97%B6
[4]前端缓存 API 请求数据的解决方案: https://blog.csdn.net/qq_41581588/article/details/128565077
[5]PLUS 前端 H5 性能优化实践: http://sd.jd.com/article/2195?shareId=3946&isHideShareButton=1
本文分享自微信公众号 - 凹凸实验室(AOTULabs)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
|