前端性能优化(上)
性能优化调研系列文章
为什么要进行前端性能优化?
用户体验-> 用户留存 -> 用户转化 -> 收益转化
Google在开发者文档《为什么性能优化如此重要》 从四个角度阐述了性能的重要性
Performance is about retaining users(用户留存)
加载时长和页面放弃关系加载时长和页面放弃关系
正向例子:
- Pinterest reduced perceived wait times by 40% and this increased search engine traffic and sign-ups by 15%.
- COOK 的转化率提升 7%、丢出率下降 7%,且每次会话浏览页数增加 10%,得益于其页面平均加载时间减少 850 毫秒
反面例子:
Performance is about improving conversions (转化率)
-
对于Mobify来说,首页加载速度每降低100毫秒,基于会话的转化率就提高了1.11%,平均每年的收入增加了近380,000美元。此外,结帐页面加载速度降低100毫秒,基于会话的转化率提高了1.55%,这反过来又使年均收入增长了近$ 530,000
-
AutoAnything 发现当他们减少一半的页面加载时间,会提升12%-13%的成交额。
Performance is about user experience(用户体验)
- 性能是好的用户体验的基础。
- 现代web应用,前端承载了越来越多的逻辑和职责,导致应用越来越大(相反,真实用户的网络和设备性能却千差万别)
其中引用的一篇《流式传输会延迟智能手机用户的心理负担:爱立信移动报告》非常有意思。
调研报告显示: 视频加载的延迟会使用户的心率平均上升37%,等同于看恐怖电影或者参加数学考试一样给人带来的压力(恐怖电影 没啥感觉,数据考试可能大家都有比较深的感触~)
Performance is about people(以人为中心)
- 减少你站点加载的资源大小,不要没到月底,流量套餐就用完了,或者被限速!!!(同样也会为公司减少CDN支付的费用哦~)
- 医院,诊所和危机中心等公共资源具有在线资源,这些资源为用户提供了危机期间所需的重要和特定的信息。尽管设计对于在紧张时刻有效地展示重要信息至关重要,但快速提供这些信息的重要性不可低估
以上基本上对Google在开发者文档《为什么性能优化如此重要》的总结。
性能优化指标
上面基本上说明了性能优化的重要性,但是怎么确定我们的应用性能好与坏呢? 用户体验是最直接以及最终的要得到的效果,但是体验(感觉)又是一个抽象,主观意识,非量化的方式。
在传统的web页面中(jsp、或者smarty)服务端模板渲染的应用中(通常也不会包含很多的前端异步渲染请求、渲染逻辑)关注的可能是onload DOMContentLoaded
时机。
然后在今天2020年的节点上 显然这些已经无法真正测量页面的性能了。我们需要合理的定义性能指标(Performance Metrics)
Google 根据一些原则定义了一些通用的指标
image.png关于指标定义:
- google的性能指标也在不断的调整
- google的一些指标不一定对所有的业务场景都适用
- 我们可能需要定义一些自定义的性能指标
这些指标如何测量呢?
两种方式
- 实验室数据: 在一个稳定可控的环境中使用工具模拟页面加载过程,采集相关指标。
- 线上真实用户数据: 采集线上用户真实的加载和交互过程中的指标。
这两种方案,在没有设定背景的情况下,并没有优劣之分。在团队发展的不同阶段,项目的不同阶段,具体问题的发生的背景下,去选择合适的方案。长期来看线上数据采集是一个刚需,因为我们最终要交付的对象是真实的用户,而用户的真实使用环境(网络、性能等)我们无法揣测。
- 2020-7月份 安卓联网方式 分布(数据来源:百度流量研究院) 百度统计数据 网络连接方式分布
- 2020-7月份 IOS联网方式 分布(数据来源:百度流量研究院) image.png
实验室采集工具:
线上采集(构建线上性能监控体系)
使用lighthouse进行性能测试
通过lightouse
大致测量你的页面的性能表现,观察各个性能指标的得分。
// 使用命令行
lighthouse https://www.oklink.com/ --view --emulated-factor-form='mobile' --output-path='oklink.com.html'
lighthouse 移动端默认使用的网络预设是, 在chrome的 devtool中有个网络限流,选项是:Fast 3G就是这个配置
Latency: 150ms
Throughput: 1.6Mbps down / 750 Kbps up.
Packet loss: none.
这样的话,模拟移动端的最大下载速度就是 200k。
FCP
Fisrt Contentfull Paint 指标测量了从开始加载到第一次绘制任何的text(包含引用加载中字头文件的text)、image(包括背景图)非白色的canvas、svg元素的时间。
含义
衡量的维度:Is it happening? Did the navigation start successfully? Has the server responded?
FCP 和 FP 的区别
- First Paint 发生在导航阶段完成之后的第一次渲染. 不包含默认背景色(比如默认背景色的body)但是包含非默认背景色(设置背景色的body)
- Fisrt Contentfull Paint 发生在导航阶段完成之后,第一次绘制任何的text、image(包括背景图)非白色的canvas、svg元素、包含引用加载中字头文件的text。
- FP 在 FCP 之前或者同时触发。
- 触发FP的第一次绘制 不一定触发FCP,触发FCP的条件一定能触发FP。
参考demo:https://github.com/webaifei/performance-demos/blob/master/src/templates/fp.html#L16&L23
怎么计算
- 使用工具: lighthouse 、pageSpeed等
- 使用web-vitals
- 使用Paint Timing API
多快算好
目前lighthouse V6 移动测评的时候, 给出评分规则,小于2.3s,会给出90+的分数。
LCP
Largest contentfull paint 指标上报可视窗口内,最大的图片或者文本绘制时间。
含义
衡量的维度: Is it useful? Has enough content rendered that users can engage with it?
计算逻辑
哪些元素被被考虑作为最大元素
- img
- svg中的image
- 一个元素 使用background-image (但是不是使用 CSS gradient)
- 块级元素(包含了 文本内容或者是行内文本元素)
- 使用了poster属性的video元素
元素的大小如何计算?
- 只计算用户可视区域范围的可见元素:如果元素设置了
visibility opacity display
不可见 是不会计算在内的。 - 如果一个元素一部分超出了可视区域,或者被父容器使用overflow等属性隐藏掉,则这部分不可见的部分不会计算在内。
- 对于image图片元素,有两个大小:图片真实的大小和在可视区域内的展示的大小,上报时候取两者的最小值进行计算。
- 对于text文本元素,只考虑能包含文本的最小矩形区域。
- 对于所有的元素,任何通过css设置的margin、padding、border都不会计算在内。
参考demo: https://github.com/webaifei/performance-demos/blob/master/src/templates/lcp.html
什么时候会上报LCP?
因为web 页面加载是分阶段的,在渲染的过程中,largest element 可能会变化。 所以Largest Contentful Paint API 会在largest element发生变化的变化的时候 不断的触发上报。
具体哪些情况下 最大元素可能发生变化
- 新添加DOM元素(元素属于最大内容的备选项)
- 删除一个DOM元素(元素属于最大内容的备选项)
- 修改DOM元素的属性:opacity display visibility, src(元素属于最大内容的备选项)
注意: 改变元素的大小和位置 不会再次触发LCP 上报,对于图片资源在加载完成之后 修改大小和位置不会再次触发LCP上报。
什么时候停止上报?
- 用户在页面上发生交互(因为用户操作经常会修改元素的可见性)
怎么计算
- 使用工具: lighthouse 、pageSpeed等
- 使用web-vitals
- 使用Paint Timing API
多快算好
目前lighthouse 移动评分 低于2.5s,被认为是一个较好的表现,给出了90+的分数。
TTI
Time to interactive 指标测量从页面开始加载到页面依赖的主要的子资源加载完毕并且能够快速可靠的响应用户的输入
含义
衡量的维度:Is it usable? Can users interact with the page, or is it busy?
计算逻辑
TTI 定义上比较抽象,那么是怎么测量:主要的子资源加载完毕并且能够快速可靠的响应用户的输入
- 从FCP时间点开始
- 向前(时间线上其实是指之后的时间)立即搜索一个长达5秒钟的静默窗口
- 从找到的静默窗口之前,向后(时间线上其实是指之前的时间)搜索最近的一次long task ,如果没有找到就停在FCP发生的时间点。
- TTI 就是静默窗口之前的最近一次long task的结束时间,如果没有找到long task 那就是FCP的时间点。
5秒钟的静默窗口被定义为:
1. 期间没有long task运行
2. 没有超过两个的进行中的网络请求
TTI
<figcaption style="margin-top: 5px; text-align: center; color: #888; font-size: 14px;">TTI</figcaption>
如何计算
- 使用lighthouse 等
- 使用 google提供的tti-polyfill
参考demo:https://github.com/webaifei/performance-demos/blob/master/src/templates/tti.html
多快算好
google建议为了提供良好的用户体验,在移动设备上,TTI 要尽量少于5s
目前lighthouse 移动评分 5s的TTI 得分为77分。
优化手段
待补充。
TBT
Total block time 指标统计了从FCP开始到TTI结束之间的所有long task超过50ms部分的时间总和。
含义
衡量的维度:Is it usable? Can users interact with the page, or is it busy?
怎么计算
假设下面是FCP -> TTI 之间的所有运行的tasks image那么总的TBT=200+40+105
多快算好
google 建议TBT 时间<300ms 目前lighthouse 移动评分 低于300ms,会给出90+的分数。
知道了这些指标的含义和计算规则,我们就可以开始优化那些得分较低的指标了。但是在这之前,先来了解下《浏览器的加载、渲染过程》,会对我们的性能优化工作有非常大的帮助。