小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
前言
Performance可以给我们提供非常多的信息,但Performance不够直观,需要开发者透过表面的这些参数去分析背后的性能问题。有了这个诉求之后,另一个性能优化工具就出现了,它就是LightHouse。
LightHouse 是 Google 开源的一个自动化工具,用于改进网络应用的质量。你可以将其作为一个 Chrome 扩展程序运行,或从命令行运行。 当为 Lighthouse 提供一个要审查的网址,它将针对此页面运行一连串的测试,然后生成一个有关页面性能的报告。可以参考失败的测试,看看可以采取哪些措施来改进应用。
6大测量指标优化策略排序
Largest Contentful Paint 【简称LCP: 最大内容渲染】
FCP最大内容渲染时间标记了渲染出最大文本或图片的时间
Total Blocking Time 【简称TBT: 总阻塞时间】
TBT测量了FCP(首次内容渲染)和TTI(可交互时间)之间的总耗时。TTI可能会被主线程阻塞以至于无法及时响应用户。大于50ms的任务称为长任务,当任意长任务出现时,主线程则称为被阻塞状态。由于浏览器不会打断正在进行中的长任务,所以,如果用户在执行长任务时和页面有交互事件时,浏览器必须等到该长任务完成才能响应。TBT计算的是在FCP到TTI之间所有长任务时间内总和。
如下图所示,我们有5个任务,其中有3个是长任务,因为它们的时长超过了50ms。
虽然运行任务的总时长是560ms但是只有345ms被认为是总阻塞时长。
First Contentful Paint 【简称FCP: 首次内容渲染】
FCP测量了从页面开始加载到页面任意部分的内容渲染到屏幕上。
Speed Index 【简称SI: 速度指数】
SI速度指数表明了网页内容的可见填充速度。lighthouse首先捕获页面加载的视屏,然后对比帧与帧之间视觉效果变化(通过计算结构相似指数SSMI来比较)。 如何提升SI呢?
- 最小化主线程工作量
- 减小JS的执行时间
- 确保在字体加载过程中文本可见
Time to Interactive 【简称TTI: 可交互时间】
可交互时间是指网页需要多长时间才能提供完整交互功能。TTI测量了从页面开始加载到页面的主要附属资源加载完毕,并且可以足够快速回应用户输入的所用时间。
Cumulative Layout Shift 【简称CLS: 累积布局偏移】
CLS累积布局偏移旨在测量可见元素在视口内的移动情况。CLS值越小越好。
针对各个测量指标的优化措施
措施1:优化LCP
优化弹出框,替换过大背景图片。对图片做preload。加快图片下载。
措施2:减少无用JS、CSS,减小TBT,提升SI
- 彻底
code split - 前端路由懒加载
split chunk- 微前端预加载
- 借助
Webpack Bundle Analyzer帮助我们分析项目
措施3:首图图片减小自定义首屏时间
- 小图转
base64走磁盘缓存
措施4:资源预加载
这里可以使用webpack插件来打包时增加preload属性
<!-- preload js -->
<link rel="preload" as="script" href="{js地址}" crossorigin />
<!-- preload css -->
<link rel="preload" as="style" href="{css地址}" crossorigin />
<!-- preload 图片 -->
<link rel="preload" as="image" href="{图片地址}" crossorigin />
措施5:提前建立第三方链接
注意:只对一些立即用到的第三方站点做这种preconnect处理,要省着用preconnect。 用preconnect给所有的第三方站点都做提前链接很低效,可以为重要的第三方站点做preconnect,其余的都做dns-prefetch. 可节约20-120ms。
<!-- preconnect 3rd party -->
<link rel="preconnect" href="<https://example.com>">
<link rel="dns-prefetch" href="<https://www.google-analytics.com>" />
<link rel="dns-prefetch" href="<https://cm.g.doubleclick.net>" />
措施6:减少CLS
其实布局有偏移还是很常见的。比如我们的用户信息数据,在我的页面的用户信息卡片里,是异步接口获取的。所以看到可能会是页面先加载了一部分,然后拿到数据后进度条显示并生成进度条。这种异步的内容减少CLS的方式:
- 可以想办法把这个异步接口合并到主接口里来解决,或者设置一个默认的图片占位。等数据来了再替换掉。
- useSWR:异步更新缓存策略,可参考深入浅出 useSWR 原理 - 知乎 (zhihu.com)
措施7:浏览器缓存机制
结合强缓存和协商缓存,合理地缓存静态资源,比如当我们的资源内容不可复用时,直接为 Cache-Control 设置 no-store,拒绝一切形式的缓存;否则考虑是否每次都需要向服务器进行缓存有效确认,如果需要,那么设 Cache-Control 的值为 no-cache;否则考虑该资源是否可以被代理服务器缓存,根据其结果决定是设置为 private 还是 public;然后考虑该资源的过期时间,设置对应的 max-age 和 s-maxage 值;最后,配置协商缓存需要用到的 Etag、Last-Modified 等参数。
其他措施
当把lighthouse给出的opportunities和diagnosis都做到了以后,可考虑
- 减少服务端TTFB,需要后端优化主接口。
- 第三方脚本治理:能优化就优化,不能优化的想办法置后加载,避免阻塞主js。
优化后的结果对比
优化前
优化后
Network throttling 150 ms TCP RTT, 1,638.4 Kbps throughput (Simulated)
Network throttling 40 ms TCP RTT, 10,240 Kbps throughput (Simulated)
| 标题 | |
|---|---|
Lighthouse的盲区
事实上Lighthouse是一个性能测试工具,并不能完全代表用户的真实体验。我承认如果单纯是为了跑分,完全可以使用一些其他的方法可以提升分数,但这些方法会使得在使用过程中体验很差,因此放弃了。当我们使用Lighthouse的时候,基于都是宿主机器的性能结果,虽然我们可以限制网速和CPU等等,但和现实还有有所差距。
因此我们可以把Lighthouse当成是一个集成性能测试工具。为我们提供标准的性能报告,在使用过程中我们可以将其集成于CD流程,作为测试的一种,保证我们上线的功能在大多环境下有着优秀的表现。