diff --git "a/source/_posts/2023-04-04-\345\211\215\347\253\257\346\200\247\350\203\275\344\274\230\345\214\226.md" "b/source/_posts/2023-04-04-\345\211\215\347\253\257\346\200\247\350\203\275\344\274\230\345\214\226.md" new file mode 100644 index 0000000000..d27ef111ad --- /dev/null +++ "b/source/_posts/2023-04-04-\345\211\215\347\253\257\346\200\247\350\203\275\344\274\230\345\214\226.md" @@ -0,0 +1,325 @@ +--- +title: 实践指南-前端性能提升 270% +subtitle: 实践指南-前端性能提升 270% +cover: +categories: 前端开发 性能优化 +tags: + +- web开发 +author: + nick: 唐姣 + github_name: jiaozitang +date: 2023-04-04 10:00:00 + +--- + +![cover](https://img14.360buyimg.com/ling/jfs/t1/219666/3/25422/187127/642bd306F166d9f33/62ee73264ec76e6c.jpg) + +## 一、背景 + +当我们疲于开发一个接一个的需求时,很容易忘记去关注网站的性能,到了某一个节点,猛地发现,随着越来越多代码的堆积,网站变得越来越慢。 + +本文就是从这样的一个背景出发,着手优化网站的前端性能,并总结出一套开发习惯,让我们在日常开发时,也保持高性能,而不是又一次回过头来优化性能。 + +先来看看优化的成果,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% | + +优化前后对比: + +![优化前后对比](https://img30.360buyimg.com/ling/jfs/t1/165203/31/36160/300424/642bbf22Fc6f16671/60d1c883cbc521ff.png.webp) + +## 二、优化前 + +接下来就是介绍下优化前我们要做哪些事件: + +1. 了解性能指标及测量工具 +2. 分析需要优化的地方 + +### 1. 了解测量工具及性能指标 + +一开始我们只是感受到网站的页面打开时白屏时间较长,感觉性能是比较差的,那么具体有哪些性能指标需要去关注呢? + +这里我使用的是 Chrome devtools 内置的 [Lighthouse](https://developer.chrome.com/docs/lighthouse/),Lighthouse 是一种开源的自动化工具,用于提高 Web 应用程序的质量。 + +Lighthouse 会在一系列的测试下运行网页,比如不同尺寸的设备和不同的网络速度。它还会检查页面对辅助功能指南的一致性,例如颜色对比度和 ARIA 最佳实践。 + +打开 Chrome devtools Lighthouse 即可使用。 + +在比较短的时间内,Lighthouse 可以给出这样一份报告。 + +这份报告从 5 个方面来分析页面: 性能、辅助功能、最佳实践、搜索引擎优化和 PWA。像性能方面,会给出一些常见的耗时统计。 + +![优化前](https://img13.360buyimg.com/ling/s800x0_jfs/t1/113682/26/36252/160266/642bbf7aFe03af0e8/3155447cded83669.png.webp) + +#### 1.1 Performance + +Performance 评分统计,包括了以下指标: + +##### 1.1.1 FCP + +FCP 测量在用户导航到页面后浏览器呈现第一段 DOM 内容所花费的时间。页面上的图像、非白色``元素和 SVG 被视为 DOM 内容;不包括 iframe 内的任何内容。 + +##### 1.1.2 LCP + +LCP 测量视口中最大的内容元素何时呈现到屏幕上。这近似于页面的主要内容对用户可见的时间。 + +需要注意的是 LCP 的计算是一个动态的过程,如下图最后的图片才是这个页面中的最大内容绘制的元素。 + +![lcp](https://img13.360buyimg.com/ling/jfs/t1/97921/25/37599/505228/642bc02fFdb0a7617/55bdbab3841345b2.png.webp) + +##### 1.1.3 TTI + +TTI 测量页面完全交互所需的时间。 + +TTI 是如何计算的呢,如下图首先延时间轴正向搜索时长至少为 5 秒的安静窗口(安静窗口是指没有长任务且不超过两个正在处理的网络 get 请求),然后沿时间轴反向搜索安静窗口之前的最后一个长任务,如果没有找到长任务,则在 FCP 步骤停止执行,TTI 就是安静窗口之前最后一个长任务的结束时间,如果没有找到长任务的话,则与 FCP 值相同。 + +![TTI](https://img20.360buyimg.com/ling/jfs/t1/178971/40/34450/64381/642bc141F122ee65e/163dcf1ddabe5a63.png.webp) + +##### 1.1.4 Speed Index + +Speed Index 衡量页面加载期间内容以视觉方式显示的速度。Lighthouse 首先捕获浏览器中页面加载的视频,并计算帧之间的视觉进度。 + +##### 1.1.5 TBT + +TBT 测量页面被阻止响应用户输入(例如鼠标点击、屏幕点击或键盘按下)的总时间。 + +通过添加 First Contentful Paint 和 Time to Interactive 之间所有长任务的阻塞部分来计算总和。任何执行时间超过 50 毫秒的任务都是长任务。 + +50 毫秒后的时间量是阻塞部分。例如,如果 Lighthouse 检测到一个 70 毫秒长的任务,则阻塞部分将为 20 毫秒。 + +如下图淡红色区域的时间总和就是这个页面的 TBT 分数。 + +![TBT](https://img10.360buyimg.com/ling/jfs/t1/158514/38/37114/24398/642bc1d4Fc0f18ca7/3c94635bcf517fc0.png.webp) + +#### 1.2 最佳实践 + +用于检测 Web 应用程序整体代码健康状况,包括是否包含文档类型、图片宽高比是否正确等等。 + +#### 1.3 SEO + +用于检测搜索引擎对网页内容的理解程度。 + +### 2. 分析需要优化的地方 + +了解了关键的性能指标后,就可以测量看看当前网站的性能了, + +上面看到综合评分是非常低的,Lighthouse 给出了应该从哪些地方开始优化的建议。 + +#### 2.1 Performance + +性能优化建议主要包括以下几点: + +- 减少未使用的 JS; +- 合理使用图片的格式,webp 或者 avif 更快; +- 延迟加载不在视图的图片; +- JS 压缩; +- 图片的尺寸大小应该适当; +- 减少未使用的 CSS。 + +![性能优化建议](https://img10.360buyimg.com/ling/s800x0_jfs/t1/217931/13/26408/85209/641aff78F14b48114/2e449063eceea125.png.webp) + +Lighthouse 诊断出的网站存在的问题: + +- 需要加载的资源太多太大,有 147 个请求,合计 11mb; +- 有 40 个静态资源的缓存只有 1 小时 +- 滚动事件没有添加标记`{passive: true})`,导致需要等待侦听器完成执行后再滚动页面; +- 图像元素没有设置明确的宽度和高度; +- JS 文件太多,主线程工作量太大、JS 执行时间太长; + +![存在的问题](https://img12.360buyimg.com/ling/s800x0_jfs/t1/219688/15/27025/181094/641afff4F84ac0f8c/487d9de6f2678b4f.png.webp) + +#### 2.2 最佳实践 + +最佳实践方面有以下问题: + +- 图片的分辨率太低,清晰度不够; +- 没有设置 CSP 策略。 + +![最佳实践的问题](https://img13.360buyimg.com/ling/s800x0_jfs/t1/109028/18/33112/99796/641b03afF4073ce91/a02c61830aaeafc3.png.webp) + +#### 2.3 SEO + +SEO 有以下问题: + +- 没有 meta description; +- 图片没有 alt 属性; +- robots.txt 是无效的。 + +![SEO的问题](https://img20.360buyimg.com/ling/s800x0_jfs/t1/103369/1/38905/118351/641b0489F59920b88/2b4138c95337db97.png.webp) + +## 三、优化 Performance + +根据上面 Lighthouse 报告,捋一捋项目中影响性能最大的因素,包括以下几点: + +- 体积太大,达 11mb; +- 图片太大,图片格式也有影响。 + +### 1. 体积优化 + +#### 1.1 代码压缩 + +检查是否还有压缩空间,或者有无工具库未压缩的。 + +#### 1.2 代码分包 + +通过 webpack-bundle-analyzer 插件分析包体积,将一些大的 npm 包和 runtimeChunk 独立分包,减小包体积。 + +#### 1.3 组件按需加载 + +React.lazy + Suspense 封装懒加载组件,路由级组件引入懒加载组件。 +同时使用骨架屏作为懒加载的兜底组件,可以让用户感知加载更快。 +在鼠标移入导航栏时预加载路由组件,可以加快页面展示。 + +#### 1.4 工具库按需加载 + +通过 import('xx').then(xx) 按需加载工具库。 + +#### 1.5 静态资源上传 CDN + +项目内有一些 json 文件存储的静态数据,这部分文件上传至 CDN,改为 fetch 的方式按需引入。 + +#### 1.6 删除不需要的资源 + +检查项目中引入的 mf、npm 资源,将没有使用到的删除。 + +#### 1.7 避免重复的 npm 包引入 + +发现业务组件库通过 npm 引入的原子组件库,而项目本身又是通过 mf 引入的原子组件库,相对于引入了 2 遍原子组件库。 + +这时就需要改造业务组件库,也改成用 mf 的方法引入。 + +#### 1.8 避免 esm 依赖嵌套 + +因为 webpack 的按需加载是通过 import、export 来标记的,因此想要一个好的按需加载的效果,就需要避免依赖嵌套的问题。 + +#### 1.9 图标按需加载 + +原子组件库 mf 暴露的方式会导致只用了 1 个 icon,就会加载组件库下所有 icon 对应的 chunk,导致资源浪费。 + +新建一个 icon 的 npm 包用于 icon 的按需引入。 + +#### 1.10 小结 + +通过以上优化手段,体积从 11.7mb 降低至 1.1mb,降低 10.6 倍。 + +优化前: + +![优化前](https://img30.360buyimg.com/ling/s800x0_jfs/t1/142577/37/35594/193379/641b205fFc53e6e7f/8054e11e4b1539d3.png.webp) + +优化后: + +![优化后](https://img10.360buyimg.com/ling/s800x0_jfs/t1/188969/6/33839/125463/641b1f75F09f05646/dff8da057e966e3d.png.webp) + +### 2. 图片优化 + +#### 1.1 图片懒加载 + +对非首屏的图片采用图片懒加载策略。 + +#### 1.2 图片尺寸 + +使用图片时,设置图片的合理尺寸。 + +#### 1.3 图片格式设置 + +优先使用 webp 格式图片。 + +## 四、优化最佳实践 + +### 1. 设置 CSP 策略 + +### 2. 设置合理的图片的分辨率 + +优化项目内的图片分辨率。 + +## 五、优化 SEO + +### 1. meta description、keywords 优化 + +详细的 meta description、keywords 可以加快 SEO。 + +```html + +``` + +### 2. 图片加上 alt 属性 + +```html +Smiley face +``` + +## 六、优化前后对比 + +再来回顾下前后对比: + +优化前,明显的感知白屏时间长: + +![优化前](https://storage.360buyimg.com/jelly-client/1.gif) + +优化后,在清缓存的情况下也能实现秒开: + +![优化后](https://storage.360buyimg.com/jelly-client/2.gif) + +整体性能提升 270%: + +![优化前后对比](https://img30.360buyimg.com/ling/jfs/t1/165203/31/36160/300424/642bbf22Fc6f16671/60d1c883cbc521ff.png.webp) + +## 七、性能监控 + +为了在后续的迭代过程中,保持高性能,引入内部前端监控平台 - [烛龙](http://dra.jd.com/),可视化的监控前端性能。 + +第一步,加载 cdn 插件: + +```html + +``` + +第二步,在入口文件中,初始化 cdn 插件: + +```jsx +useEffect(() => { + // 初始化测速组件,在这里可以打开一些控制的开关,如是否上报接口 + if (IS_PROD) { + // @ts-ignore + jmfe.profilerInit({ + flag: 379, // 这是应用ID,需要先在烛龙申请应用 + autoReport: true, + autoAddStaticReport: true, + autoAddApiReport: true, + autoAddImageReport: false, // 支持所有图片上报,如果图片多,切记关闭,否则存在性能问题 + performanceReportTime: 8000, + profilingRate: 1, + }) + } +}, []) +``` + +第三步,查看监控数据: + +在烛龙平台,小工具性能评分达 96分: + +![查看监控数据](https://img14.360buyimg.com/ling/jfs/t1/149949/1/36661/109295/642bc9d4F0559f2e2/bee119d691a8ba25.png.webp) + +## 小结 + +本文详细介绍了一个前端项目优化的详细过程,从优化前的问题分析,到具体的优化措施,最终实现了前端性能提升了近 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) +- [前端缓存 API 请求数据的解决方案](https://blog.csdn.net/qq_41581588/article/details/128565077) +- [网易云课堂 Service Worker 运用与实践](https://mp.weixin.qq.com/s/3Ep5pJULvP7WHJvVJNDV-g) +- [PLUS 前端 H5 性能优化实践](http://sd.jd.com/article/2195?shareId=3946&isHideShareButton=1)