前端性能方面的研究一直都未中断过,由此所产生的一些性能衡量指标也是不断地在改进,lighthouse的指标和权重目前就已经改过很多个版本了。
客观上来看,性能都是相对的,前端页面有ToC、ToB,有单页应用,有pwa也有移动端页面,各页面的类型不同,功能不同,体量也有着相当大的差距,但从用户使用的角度来讲,用户不会太过区分前端页面有着多重的功能,用户大多关心的是网页打开速度快慢,以及在使用过程中的体验。
所以针对性能方面,前端应用需要参考通用性的性能指标,也需要额外在针对性的功能上有着相应的指标来衡量。
一、核心指标
每一个时代都有着前端所追求的web性能体验标准,2020年,“Core Web Vitals”是google的新一轮衡量标准,它包含了三个方面:最大内容绘制(Largest Contentful Paint,LCP),首次输入延迟(First Input Delay,FID)和累积布局偏移(Cumulative Layout Shift,CLS),分别对应了加载体验、交互性和视觉稳定性。
1、LCP
在视窗内可见的最大内容的渲染时间。这类的内容指文本、图像(包括背景图)、svg元素或非空白的canvas元素。详细说明及计算:Largest Contentful Paint
2、FID
衡量的是从用户第一次与页面进行交互(单击链接,点击按钮或使用自定义的JavaScript驱动的控件)到浏览器实际上能够开始处理事件处理程序的时间。
FID与TTI(Time to Interactive)的区别:(FID通常获取线上环境的用户数据来测量,TTI可由本地测试环境测量)
3、CLS
测量在页面的整个生命周期中发生的意外布局移动的所有单个布局移动得分的总和。
当可见元素的位置从一个渲染帧改变到下一个渲染帧时,就会发生布局移动(layout shift)。而只有现有可见元素的起始位置变动才算是布局移动,如果新插入一个元素或者元素不改变位置只改变大小等,只要它没有引起其他可见元素的位置变动,就不算入布局移动中。
当用户有主动交互时,500ms之内的发生的布局移动不在得分计算之内。
CLS分数计算为影响区域分数和移动距离分数的乘积,影响区域得分是元素的可见区域位置变化面积除以总视窗面积,移动距离得分是在一帧中元素位置移动的最大距离除以视窗最大尺寸(宽或高)。
CLS可能发生在每一帧之间,所以在lighthouse中能测得的只是在加载过程中的数据情况,使用chrome devtools的performance面板可以随时记录并查看交互过程中发生的CLS。CLS较高时会被标记出来:
这里需要注意的是,页面的具体性能是相对的,它基于页面所处的环境,因用户所使用的网络、电脑硬件、安装的软件/插件、交互方式甚至地域等不一致,页面所表现出的性能也有着较大差异。
衡量性能的时候一般分为lab和field环境,为了方便识别这里直接称作测试(实验室)环境和线上环境,测试环境指的是在一致、受控的环境中模拟页面加载,而线上环境则是用户们真实的操作环境。
测试环境可以通过工具在稳定的环境测量性能数据,在需要衡量性能的功能尚未发布前,使用测试环境来测量能较好地控制页面性能,防止性能体验下降,也有利于和竞品等进行数据对比。但是基于测试的环境下,并不能很好地反映出广大用户在使用前端应用时的真实体验,所以线上环境下的性能数据收集也是必要的,是衡量网站效果的主要手段。
需要注意的是在本地测试的时候,最好使用无痕模式来进行,避免过多的浏览器插件对结果造成影响。
用户的环境多种多样难以控制,难免有极个别的异常值会影响性能统计,因此Google才有了标准中75百分位的选择,此百分位的数据受异常值影响的可能较小且能反映出大多数网站访问的性能。
本文中列出的指标值均以线上环境性能数据为主,而在本地测试中则会有无缓存和有缓存下两种较为有差距的数据产生,推荐以无缓存下相关性能为主,有缓存下性能数据作为对比参考。
二、Lighthouse中的性能指标
1、First Contentful Paint(FCP)
测量用户打开页面后浏览器呈现的第一个DOM内容所花费的时间(不包括iframe中任何内容)。权重:15%。
2、Speed Index(SI)
衡量页面加载过程中内容从视觉上呈现的速度。(通过speedline计算得分)权重:15%。
3、Largest Contentful Paint (LCP)
同核心指标。权重:25%。
4、Time to Interactive (TTI)
页面变为完全可以交互的状态所耗费的时间。(计算及说明参见First Interactive and Consistently Interactive)权重:15%。
5、Total Blocking Time (TBT)
衡量页面加载过程中阻塞用户操作的时长,总时间由FCP到TTI之间的所有长任务的阻塞时间相加得出。长任务(long task)的阻塞时间说明:执行时间超过50ms的任务都算做长任务,50ms之后的耗时便是阻塞时间,例如一个70ms的任务,其阻塞时间便为20ms。权重:25%。
6、Cumulative Layout Shift (CLS)
同核心指标。权重:5%。
三、其他参考指标
1、Dom Content loaded(DCL)
初始的HTML文档被完全加载和解析完成之后会触发DCL事件,无需等待样式表、图片和子框架的完全加载。
2、onLoad (L)
在文档完全加载完成时会触发,包括图片、脚本、链接及子框架。影响浏览器标签上loading状态。
3、First Paint (FP)
页面导航与浏览器将网页的第一个像素渲染到屏幕上所用的时间,即任何与输入网页导航前屏幕上内容不同的渲染的时间。
4、First Meaningful Paint(FMP)
衡量用户何时能看到页面的主要内容。也是lighthouse 5的指标之一,但是由于此指标定义依赖于特定浏览器的实现细节,无法实现标准化,计算结果也会因页面加载中的微小差异而产生不一样的结果,因此被LCP所取代,其技术细节可参考Time to First Meaningful Paint
5、First CPU Idle
测量页面变为能进行最低限度的交互所花费的时间。当页面准备好为用户输入时,First CPU Idle 和TTI都将开始进行测量,用户可以开始同页面进行交互时,发生First CPU Idle ,当用户能最大程度同页面交互时,发生TTI。lighthouse 5的指标之一,建议改为使用TBT、TTI。
6、Time To First Byte(TTFB)
发出页面请求到接收到应答数据第一个字节的时间总和,首字节指的是收到的HTTP头的第一个字节。此指标跟服务器方面的优化有关,可作参考。
7、PerformanceTiming相关
performance.timing 只读属性返回一个 PerformanceTiming 对象,这个对象包括了页面相关的性能信息。
四、用户体验相关:
1、RAIL模型
以用户为中心的性能模型,它旨在让用户满意网站的体验,详细说明可见:RAIL介绍
响应
在50ms内下处理事件
目标:在100毫秒内响应用户输入,让用户感觉交互是即时的。
动画
在10ms内产生一帧
目标:在10ms或更短的时间内生成动画中的每一帧。 从技术上讲,每帧的最大预算是16ms(1000ms/每秒60帧≈16ms),但是浏览器需要大约6ms才能渲染每帧,因此这里定为每帧10ms。
空闲
最大化空闲时间
目标:最大化空闲时间,以增加页面在50毫秒内响应用户输入的几率。
加载
在5秒内传递内容并响应交互。
目标:相对于用户的设备和网络功能,优化快速加载性能。目前,在3G连接速度较慢的中档移动设备上,第一次加载的一个好目标是加载页面并在5秒或更短时间内实现交互,后续的加载应在2秒内完成。(pc端应在1秒内加载完成)
RAIL中部分数据需要在加入相关代码埋点统计后才能看到,否则较难以直观地查看性能数据的统计情况,在本地的实验室测试环境中也可以通过chrome devtools的Performance面板来进行记录观察。上述目标中都是以用户为中心而设定的,基于人类相对稳定的感知,并且不太可能在短期内改变。RAIL也并不是追求所有情况下网站都能达到预期目标,它意在提供一个性能优化的方向。
2、FPS指标
FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。FPS是测量用于保存、显示动态视频的信息数量。每秒钟帧数越多,所显示的动作就会越流畅。
交互中达到16.66ms完成一帧是最理想的情况,由于功能原因,有不少大数据的复杂展示等等会消耗较长时间,在FPS小于24时用户能明显感知到页面卡顿,而达到30以上则会显得较为连贯,48-60之间则会感觉交互动画十分流畅。
FPS可以使用chrome devtools中的rendering面板,开启FPS meter查看:
不过在chrome 85版本以上,fps面板展示的数据已经有所变更,会展示页面渲染的丢帧情况:
通过本地查看一段时间内的平均FPS还有个小技巧:将开发者工具选择为窗口打开,选择需要查看平均FPS的一段记录,然后打开开发者工具的开发者工具,在控制台可以调用相应api来进行计算:
function avgFPS() {
const startTime = UI.panels.timeline._flameChart._model._window.left;
const endTime = UI.panels.timeline._flameChart._model._window.right;
const frames = UI.panels.timeline._flameChart._model._frameModel._frames
.filter(frame => (frame.startTime > startTime) && (frame.endTime < endTime));
const duration = (frames[frames.length - 1].endTime - frames[0].startTime) / 1000;
const average = frames.length / duration
return +average.toFixed(2)
}
五:总结
性能指标众多,但是许多都有互相替代性,有一些也无法在各浏览器之间标准化,因此在平时衡量的时候推荐选择性能指标:
加载:FCP、LCP
交互:CLS、FID(线上环境)、TBT(实验室环境)、TTI(实验室环境)
流畅性:FPS
FCP、LCP、CLS、FID使用web-vitals可以方便计算出,并可以获取线上用户的性能数据。也可以在本地通过performance面板reload页面来得出:
点击相应标签在下方summary可以看到详情描述。(chrome85版本对于指标的显示时间计算有所更改,从点击按钮算起变成了从url导航算起,目前看来似乎DCL的时间显示有些问题!)
FPS统计目前需要通过requestAnimationFrame计算每一帧的情况,如果发布到线上,势必会影响用户的体验,建议在本地测试。
其余指标部分未列出衡量标准,因前端页面功能有差异,难以有一个平均的标准,可以查看网页加载性能统计参考其中部分指标:https://httparchive.org/reports/loading-speed ,该网站会不断抓取分析网站信息,能反映出网络发展的一些历史情况。
前端性能指标的介绍到此为止,目标设定好了,接下来就是各种优化实践了~
下期会介绍下长列表的性能优化实践,如何分析性能瓶颈所在,如何提升长列表交互性能,敬请期待~