我们一直挂在嘴边的性能优化,到底指的是什么?

Hello,大家好,我是 Sunday。

性能优化 与 网络安全 问题一直是前端面试中的高频问点,特别在中大厂面试中,尤其如此。最近 1v1私教训练营 中很多同学就在面试中被问及到了前端性能优化相关问题。

那么我们平常所挂在嘴边的性能究竟指的是什么呢?而性能优化又应该以什么为标准进行衡量呢?今天这篇文章,把这些统统告诉你

本文为译文,原文:medium.com/gitconnecte...


前端页面性能一直是大家持续关注的问题,因为用户留存率与页面加载性能密切相关。据Google数据统计,当页面访问时长从1s增加到3s时,用户的跳出率增加了32%。

评估前端页面性能一般有两种形式:一种是利用性能分析工具在线对各项指标进行打分评估;另一种是使用性能监控,通过Performance API或自定义跟踪点报告用户真实的网络访问情况,然后进行统计分析。

虽然统计收集用户数据更为现实,但为了对页面性能评估有一个统一的量化标准,我们往往会选择使用标准的评分工具来评估页面性能。

在性能分析的早期阶段,我们会使用Chrome开发者工具来分析网页,包括触发load和DOMContentLoaded等事件时的查看时间。后来出现了网页分析器、WebPageTest、YSlow等一系列性能分析工具。

现在Google已经将自己开发的Lighthouse正式嵌入到开发者工具选项卡中,我们将Lighthouse视为标准评估工具。

Lighthouse 是一款开源网页性能分析工具,提供页面最佳实践的相关建议。除了能够直接在 Chrome DevTools 中使用之外,它还支持浏览器扩展(Chrome 和 Firefox)或 npm 包(Node API 或 CLI)。

Google 的 WebmeasurePageSpeed Insight等工具使用 Lighthouse 来分析页面。

1. Lighthouse的迭代及性能指标变化

Lighthouse 的第一个开源版本可以追溯到 2016 年,截至 2020 年 10 月的最新版本为 6.4.1,总共有 89 次迭代。多年来,Lighthouse 一直在更新其性能指标的选择。

在最新的6.X版本中,相比5.X版本,Google引入了三个新的性能指标:FMP(First Meaningful Paint)、FCI(First CPU Idle)和mpFID(Max Potential First Input Delay)已被移除;

添加了 TBT(总阻塞时间)、LCP(最大内容绘制)和 CLS(累积布局偏移)。以下部分将提供这些指标的详细说明。

当前的 Lighthouse(版本 6.X)

2. 如何计算页面性能分数

如下图所示,在页面性能部分,Lighthouse会评估6个关键指标的性能,并计算出页面的性能得分。

根据最新的6.X计算方法,每个性能指标都对应一个分数。例如,上图中,FCP、SI、LCP、TTI、TBT和CLS的值分别对应个体分数78、62、37、5、99和92。一般来说,指标的值越小,相应的分数就越高

这六个指标的权重分别为 15%、15%、25%、15%、25%和5% 。综合表现得分的计算方式如图所示------加权平均,共60分。

在 Lighthouse v6.0 版本中,删除了三个关键性能指标:FMP(First Meaningful Paint)、FCI(First CPU Idle)和 mpFID(Maximum Potential First Input Delay)。

我们将首先检查这三个已弃用的指标的定义,以更好地了解当前版本如何选择其指标。

1.什么是FMP,与FCP有什么区别?

说到FMP,首先要介绍一下First Contentful Paint(FCP):第一次内容渲染的时间。

顾名思义,只要浏览器第一次触发The First Page Paint事件,这个时刻就是FCP。不过,此时渲染的不一定是重要的页面信息,比如只是绘制一个标题操作栏甚至可见元素。虽然它在 Lighthouse 6.0 中得到了保留,但其在性能分数中的权重从 23% 下降到了 15%。

因此,FCP不能作为从用户角度准确衡量页面性能的指标。

在此背景下,FMP(First Meaningful Paint)应运而生。根据官方定义,FMP是指自页面加载开始以来,大部分或主要内容已经在初始屏幕上呈现的时间点。

那么FMP的时间是如何确定的呢?我们先来看最基本的计算方法:

我们首先计算布局对象的数量(使用 LayoutAnalyzer 进行测试计算)。

如下图所示,可以看出页面加载过程是布局对象逐步进入布局树并渲染的过程。

layoutAnalyzer 收集布局对象的数量,有一个名为 LayoutObjectsThatHadNeverHadLayout 的计数器,它表示新添加的布局对象的计数。

通过测试发现,与其他计数器相比,它变化最多的时刻往往是页面上最重要的元素渲染时。

因此,FMP指标的计算方法是LayoutObjectsThatHadNeverHadLayout(新添加的布局对象)经历最大变化后的下一时刻(跟随最大布局变化的绘制)。

当然,也有一些场景不适用上述情况:

  1. 如果页面很长,则在第一个屏幕中添加的不可见布局对象可能比可见布局对象多。在这种情况下,FMP 变得不准确。

  2. 加载网页字体并且文本使用后备字体进行布局但默认在加载开始后 3 秒内不绘制的情况;这也会影响FMP的计算。

对于场景1,FMP引入了"布局重要性"的概念来解决这个问题;对于场景2,FMP延迟统计以使指标更准确地反映页面状况。

然而,FMP 最终在 6.0 版本中被弃用,主要是由于以下两个原因:

  • 在生产环境中,FMP对页面的微小变化过于敏感,很容易导致结果不一致。
  • 该指标的定义很大程度上依赖于浏览器的具体实现细节,缺乏可供参考的标准化。

2. LCP已经取代FMP

上一节提到了FCP和FMP的缺点,因此W3C的性能小组一直在思考寻找一个合适的指标,更准确地反映用户看到页面主要内容的时间。

有时越简单越好。经过多方关于页面性能的讨论,终于找到了一种更准确的衡量页面主要内容是否加载的方法,那就是LCP(Largest Contentful Paint)。

LCP 是指渲染视口内最大内容元素的时间。该指标在 Lighthouse 6.0 中正式引入,在最终性能得分中所占权重高达 25%。

LCP 应该是除了 FCP 之外最容易定义的指标之一。从它的定义来看,有两个关键点:选择要比较的元素和确定它们的大小。

根据官方文档,以下元素将被视为最大内容元素的一部分:

  • <img>
  • <image>里面<svg>
  • <video>
  • 元素通过url()函数加载背景图片
  • 包含文本节点或内联文本子元素的块级元素

我们如何确定元素的大小?主要基于这四个规则:

  • 视口内可见元素的大小;如果它们超出或被剪切或遮挡在视图中,则它们不会计入元素大小。
  • 对于图像元素,大小通过取Min(实际大小,原始大小)来确定。
  • 对于文本元素,仅考虑覆盖所有文本的最小矩形区域。
  • 对于所有元素,边距、填充、边框等都不包含在计算中。

Google对该指标的评价如下:LCP是一个非常重要的以用户为中心的指标;它反映了用户级别感知的加载速度;它标记主要内容中最大内容元素的加载何时完成;较短的 LCP 时间使用户更快地感知页面可用。

3. 被废弃的FCI是什么?为什么它与TTI关系如此密切?

FCI(First CPU Idle:第一次CPU空闲),这个指标用来衡量一个页面需要多长时间才能达到最低交互标准。

最小交互性的确认需要同时满足以下两个条件:

  1. 屏幕上的大多数 UI 元素都是交互式的
  2. 页面对用户输入的响应平均在合理范围内

TTI(Time To Interactive:页面交互时间),是指页面达到完全交互状态所需的时间。

完全互动意味着满足以下所有三个条件:

  1. FCP之后,有用的内容已经呈现在页面上
  2. 已为最可见的页面元素注册了事件回调
  3. 页面对用户交互的响应在 50ms 以内

2017年,First Interactive指标分为两个指标:First Interactive和Constantly Interactive;次年7月,First Interactive更名为FCI,Constantly Interactive更名为TTI。可以看出,FCI和TTI是反映用户交互响应的两个指标。

那么最小交互性和完全交互性是如何计算的呢?在介绍具体的计算方法之前,我们需要知道这两个指标都是模糊的,并且可以在不同情况下不断优化和改进。

  • FCI最短交互时间

在主线程的时间轴中,从FMP开始,直到某个任务结束后,找到一个长度为f(t)的时间窗口W。如果W满足在其持续时间内的任何时间点都不存在超过250ms的连续任务集,并且在其结束前后1秒内不存在长任务(JS执行时间超过50ms的任务)。该任务结束的时刻就是我们定义的 FCI。其中 f(t)=4e^(-0.045t)+1。

下图中红框所示的时间点代表FCI。

  • TTI完全互动时间

从网络和主线程的时间线中,找到前5s的窗口期W。在W的周期内,应该满足以下条件:任意时刻,并发的网络请求不超过两个,且不存在超过50ms的长任务。W之前的最后一个长任务的结束时间就是我们所说的TTI。

下图中红框所示的时间点为TTI:

尽管有人指出FCI在某些时候比TTI更有意义,但它们之间的差异仍然不足以证明Lighthouse保留两个相似指标的合理性。

因此,在Lighthouse 6.0中,最终决定使用TTI而不是FCI。

4. mpFID及新增TBT指标

mpFID(最大潜在首次输入延迟)是指从用户输入到页面上实际开始处理事件回调的潜在最大延迟时间。

mpFID的具体计算方法是选择从FCP到TTI的JavaScript执行时间最长的任务,然后将该任务消耗的时间减去50ms。

但mpFID仅代表最大延迟时间,可能与用户体验到的实际延迟时间有所不同。不同时间用户获得的FID也会有所不同。因此,mpFID并不能真实反映页面对用户输入的响应时间。

在版本5.X中,计算性能分数时,mpFID权重为0并且不参与评分。尽管该指标不再出现在报告中,但它仍然保留在 JSON 数据中,并且仍然是官方认可的关键用户体验指标。

那么 TBT(总阻塞时间)到底是什么?为什么在性能报告中选择它而不是 FID?

我们先看一下它的定义:TBT是指在页面上响应用户输入时被阻塞的总累计时间。

具体的计算方法很清楚,将FCP和TTI之间所有长任务相加,并将其阻塞部分的时间加在一起,就得到了TBT。阻塞部分的时间是指长任务执行时间超过50ms的任意部分;例如,如果一个长任务总共需要 70 毫秒,那么阻塞时间将为 20 毫秒。

可以看出,与mpFID相比,TBT是一个更稳定的指标,可以更准确地反映页面对用户输入的平均延迟响应。

5.新增CLS

CLS(Cumulative Layout Shift),是用来衡量视觉界面稳定性的指标。

数据从Layout Instability API获取 ,计算方法如下:

布局偏移分数 = 影响分数 \* 距离分数

其中影响分数是指对整个视口的影响程度。例如,在下图中,如果文本占据整个视口的 50%,并且在下一帧中与上一帧相比向下移动 25%,则它会影响整个页面的 75%。因此,影响分数为0.75。

距离分数比较容易理解,它指的是整个视口的距离变化的比例。例如,在上述情况下,移动 25% 意味着距离分数为 0.25。

因此,所示演示的 CLS 值计算为 0.75 * 0.25 = 0.1875。

举例说明 CLS 如何影响用户体验:如下图所示,当用户尝试单击取消按钮时,页面上突然出现布局变化,确认按钮出现在之前取消按钮的位置......

可见,CLS是一个更加以用户为中心的新的性能评估指标。

目前,CLS 作为新添加的指标所占权重较小,仅为 5%,但 Lighthouse 已经考虑在下一个主要版本中增加其权重。

6. 一直存在的速度指数

速度指数(SI)用于衡量可见内容填充页面的速度,计算过程使用开源工具 Speedline。

Speedline记录页面的视频,并通过测量第一帧和最后一帧之间的时间差来计算速度指数的值。

值得一提的是,SI的最终得分将通过与数据库中真实网站的SI值进行比较来计算。目前,SI评分及评分标准如下表所示:

回顾上述指标的替代过程,我们可以看到,无论是从FMP到LCP、FCI到TTI、还是FID到TBT,目前在性能指标的选取上,都在朝着更加稳定的方向发展:指标的定义越来越简洁、明确,计算方法也趋于标准化。

然而,我们也应该知道,这里没有灵丹妙药。每个指标都有其局限性。很多场景下,分数低并不一定意味着页面体验差。只有了解了这些指标背后的原理,我们才能更科学地根据性能分数来评估页面。

前端训练营:1v1私教,终身辅导计划,帮你拿到满意的 offer 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~

相关推荐
余生H6 分钟前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍9 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai13 分钟前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默25 分钟前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_8572979135 分钟前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
茶卡盐佑星_1 小时前
meta标签作用/SEO优化
前端·javascript·html
Ink1 小时前
从底层看 path.resolve 实现
前端·node.js
金灰1 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
茶卡盐佑星_1 小时前
说说你对es6中promise的理解?
前端·ecmascript·es6
Promise5201 小时前
总结汇总小工具
前端·javascript