性能是前端领域始终绕不开的话题,因为性能影响用户的使用体感如何、留存率等多个方面,是衡量一个产品的重要指标之一,重要性无需赘言,那么我们该如何量化衡量性能的好坏呢?
衡量一个产品的性能有非常多的工具和指标,那么我们该掌握哪些性能指标?接下来就让我们一起看看
性能指标
接下来就让我们一起看看常见的业界较为公认的一些性能指标:
- 首次绘制(FP)和首次有内容绘制(FCP)时间
- 首次有意义绘制(FMP)时间
- 大量有意义绘制(LCP)时间
- 首屏时间
- 用户可交互(TTI)时间
- 总下载时间
接下来分别看看每个指标的含义。
首次绘制(FP)时间:对于应用页面,用户在视觉上首次出现不同于跳转之前的内容时间点,或者说是页面发生第一次绘制的时间点。
首次有内容绘制(FCP)时间:指浏览器完成渲染 DOM 中第一个内容的时间点,可能是文本、图像或者其他任何元素,此时用户应该在视觉上有直观的感受。
首次有意义绘制(FMP)时间:指页面关键元素渲染时间。这个概念并没有标准化定义,因为关键元素可以由开发者自行定义——究竟什么是“有意义”的内容,只有开发者或者产品经理自己了解。
大量有意义绘制(LCP)时间:用于衡量标准报告视口内可见的最大内容元素的渲染时间。为了提供良好的用户体验,网站应努力在开始加载页面的前
2.5秒内进行最大内容渲染。首屏时间:对于所有网页应用,这是一个非常重要的指标。用大白话来说,就是进入页面之后,应用渲染完整个手机屏幕(未滚动之前)内容的时间。需要注意的是,业界对于这个指标其实同样并没有确切的定论,比如这个时间是否包含手机屏幕内图片的渲染完成时间。
用户可交互时间:顾名思义,也就是用户可以与应用进行交互的时间。一般来讲,我们认为是 domready 的时间,因为我们通常会在这时候绑定事件操作。如果页面中涉及交互的脚本没有下载完成,那么当然没有到达所谓的用户可交互时间
总下载时间:页面所有资源加载完成所需要的时间。一般可以统计 window.onload 时间,这样可以统计出同步加载的资源全部加载完的耗时。如果页面中存在较多异步渲染,也可以将异步渲染全部完成的时间作为总下载时间。
可以通过浏览器的performance进行查看这些指标
通过图中可以看到有一个DCL(DOMContentLoaded)的指标,我们需要注意其与Load 事件的区别:其实从这两个事件的命名我们就能体会,DOMContentLoaded 指的是文档中 DOM 内容加载完毕的时间,也就是说 HTML 结构已经完整。但是我们知道,很多页面包含图片、特殊字体、视频、音频等其他资源,这些资源由网络请求获取,DOM 内容加载完毕时,由于这些资源往往需要额外的网络请求,还没有请求或者渲染完成。而当页面上所有资源加载完成后,load 事件才会被触发。因此,在时间线上,load 事件往往会落后于 DOMContentLoaded 事件。
获取性能数据
了解上述这些指标之后,接下来让我们看一下这些指标是如何计算获取
目前最为流行和靠谱的方案是采用 Performance API,它非常强大:不仅包含了页面性能的相关数据,还带有页面资源加载和异步请求的相关数据。
关于performance解析:
const window.performance = {
memory: {
usedJSHeapSize,
totalJSHeapSize,
jsHeapSizeLimit
},
navigation: {
// 页面重定向跳转到当前页面的次数
redirectCount,
// 以哪种方式进入页面
// 0 正常跳转进入
// 1 window.location.reload() 重新刷新
// 2 通过浏览器历史记录,以及前进后退进入
// 255 其他方式进入
type,
},
timing: {
// 等于前一个页面 unload 时间,如果没有前一个页面,则等于 fetchStart 时间
navigationStart
// 前一个页面 unload 时间,如果没有前一个页面或者前一个页面与当前页面不同域,则值为 0
unloadEventStart,
// 前一个页面 unload 事件绑定的回调函数执行完毕的时间
unloadEventEnd,
redirectStart,
redirectEnd,
// 检查缓存前,准备请求第一个资源的时间
fetchStart,
// 域名查询开始的时间
domainLookupStart,
// 域名查询结束的时间
domainLookupEnd,
// HTTP(TCP) 开始建立连接的时间 connectStart,
// HTTP(TCP)建立连接结束的时间
connectEnd,
secureConnectionStart,
// 连接建立完成后,请求文档开始的时间
requestStart,
// 连接建立完成后,文档开始返回并收到内容的时间
responseStart,
// 最后一个字节返回并收到内容的时间
responseEnd,
// Document.readyState 值为 loading 的时间
domLoading,
// Document.readyState 值为 interactive
domInteractive,
// DOMContentLoaded 事件开始时间
domContentLoadedEventStart,
// DOMContentLoaded 事件结束时间
domContentLoadedEventEnd,
// Document.readyState 值为 complete 的时间 domComplete,
// load 事件开始的时间
loadEventStart,
// load 事件结束的时间
loadEventEnd
}
}
根据这些事件节点,通过做差便可以计算出一下典型的指标
let times = {}
let t = window.performance.timing
// 解析 DOM 树耗时
times.analysisTime = t.domComplete - t.domInteractive
// 白屏时间
times.blankTime = t.domLoading - t.fetchStart
// 用户可交互时间
times.domReadyTime = t.domContentLoadedEventEnd - t.fetchStart
// 用户等待页面完全可用的时间
times.loadPage = t.loadEventEnd - t.navigationStart