为什么要统计监控指标
量化出一个页面的性能,根据不断阶段的耗时,找出其中的短板进行性能优化。
监控指标数据
window.performance API
performance.memory 表示内存使用情况。
performance.navigation 表示是如何导航到这个页面的,以及重定向的次数。
performance.timing 统计了页面从网页开始导航到加载完成的一些时间点,通过计算某些特定事件的时间差,从而获取中间过程的耗时,就可以得出一些用于页面性能监控的指标。
navigationStart: 准备加载页面的时间点,相当于在地址栏输入地址后回车的那个时刻。
redirectStart 表示第一个重定向的开始时间点。
redirectEnd 表示最后一个重定向的结束时间点。
unloadEventStart 表示上一个网页 upload 事件开始的时间点(当卸载一个文档时就会触发 upload 事件)。
unloadEventEnd 表示上一个网页 upload 事件完成的时间点。
fetchStart 表示浏览器准备好开始请求 HTML 文档的时间点,发生在检查本地缓存之前。
domainLookupStart、domainLookupEnd 分别表示 DNS 查询开始和结束的时间点。如果直接使用了缓存,则两者的值都等于 fetchStart。
connectStart、connectEnd 分别表示 TCP 连接开始建立和连接成功的时间点。如果没有进行 TCP 连接(比如使用 Webscoket),则两者都等于 domainLookupEnd。
secureConnectionStart 如果使用了 HTTPS,则表示连接开始时的时间点。如果没有使用 HTTPS,则值为 0。
requestStart 表示浏览器开始请求 HTML 文档的时间点,包括从本地读取缓存。
responseStart、responseEnd 分别表示浏览器收到响应的第一个字节和最后一个字节的时间点。
domLoading 表示开始解析 HTML 文档的时间点,对应 Document.readyState 改变为 loading 的时刻。
domInteractive 表示 HTML 解析完毕的时间点,对应 Document.readyState 改变为 interactive 的时刻,此时 CSS 和 JS 等其他资源还没加载完成。
domContentLoadedEventStart 表示 DOMContentLoaded 事件发生的时间点。
domContentLoadedEventEnd 表示 DOMContentLoaded 事件结束的时间点。
domComplete 表示文档和其他所有资源都加载并执行完成的时间点,对应 Document.readyState 改变为 complete 的时刻。
loadEventStart、loadEventEnd 分别表示 onload 事件触发和结束的时间点。
性能指标
- DNS 查询耗时 = domainLookupEnd - domainLookupStart
- TCP 连接耗时 = connectEnd - connectStart
- 请求响应耗时 = responseEnd - requestStart
- 白屏时间 = domLoading - navigationStart
- 首屏时间 = loadEventStart - navigationStart
- DOM 树解析耗时 = domInteractive - domLoading
- Domready 时间 = domComplete - navigationStart
- onload 时间 = loadEventEnd - navigationStart
performance.getEntries
返回值是一个包含了所有静态资源的数组,包括请求资源的绝对路径、类型、耗时等信息。
其他基于用户视觉反馈的性能指标
window.performance API 虽然提供了很多数据指标,但在某些方面依旧存在缺陷。比如:
SPA 切换路由时,performance.timing 的数据不会更新,所以无法获得每一个路由所对应的页面性能指标。
假如页面渲染出来了,但还无法响应用户的操作(JS 线程繁忙),此时 window.performance API 也没有相关的统计指标(TTI)。
FP (First Paint)
含义:首次渲染的时间点,指页面第一次有内容渲染出来的时间。
获取:可以直接通过
performance.getEntriesByType('paint')
方法获取到。
FCP (First Contentful Paint)
含义:首次内容绘制的时间点,指浏览器第一次向屏幕绘制内容。只有首次绘制文本、图片/背景图、非白色的 canvas 或 SVG 时才算数。
获取:同 FP。
FP 和 FCP 的区别:FP 是当浏览器开始绘制内容到屏幕上的时候,只要在视觉上开始发生变化,无论是什么内容触发的视觉变化,这一个时间点就叫做 FP。而 FCP 指的是浏览器首次绘制来自 DOM 的内容例如文本、图片等。所以 FP 和 FCP 可能是相同的时间,也可能是先 FP 后 FCP。
FMP(First Meaningful Paint)
Time to First Meaningful Paint
含义:首次有效绘制,指页面的主要内容开始出现在屏幕上的时间点。这里的主要内容通常等于页面渲染过中元素增量最大的点。
计算:通过 MutationObserver 监听 DOM 变化,比较哪个时刻 DOM 节点增量最大。这种计算方法存在的问题是,对于不在屏幕可视范围内的 DOM 节点,它们的渲染与否与用户体验没多大关系,所以不可见 DOM 节点的增量不应该计入到 FMP。
改良后计算方法:
还是通过 MutationObserver 监听 DOM 变化,计算当前 DOM 结构的得分,得分增量最大的那个点就是 FMP。对 DOM 的计分规则是:满足
- 挂载在 body 节点下。
- 位于屏幕可视范围之内。
- 图片节点存在有效的 src 属性。
- 非图片节点节点需宽高不为 0,且存在 textContent 或 backgroundImage。
满足以上条件的 DOM 几点称为有效节点,每个节点为 1 分。通过深度递归从根节点开始遍历,逐级计算出整个 DOM 的分数。期间如果遇到不在屏幕可视范围内的 DOM 节点,则结束向下递归,因为它的子孙节点也必然不可见。参考 fmp-tti。
- 基本上同上,不同点在于为不同类型的标签增加一个权重,每个节点的分数为这个权重值。引入权重的好处是考虑到不同标签对页面的影响是不等效的,比如 video、canvas 等有时候会比 div 等常用标签更加影响到用户体验。参考 GMTC 大前端时代前端监控的最佳实践
- 疑惑点:
- 在页面渲染的时候,就去频繁计算 DOM 得分,不是更加影响页面性能?