背景
在用户体验越来越重要的今天,关注页面性能、提升页面展现速度及交互体验逐渐成为前端开发非常重要的事情。
为了监测页面性能,chrome 开发团队就提出过监测网页性能的一些指标,比如 FP、FCP等,还有我们公司自己的北斗网站的秒开率、快开比等。但是这些指标具体怎样获取呢,今天我们就来仔细了解下这个性能监控有关的 API:PerformanceObserver。
一、历史
说起 PerformanceObserver,我们首先要了解下 Performance Timeline。
Performance Timeline 是 W3C 性能小组提出的一个规范,定义了让开发者在应用整个生命周期内收集各类性能指标的接口。
一般情况下,我们想得到某项性能记录,需要知道指定的性能事件已经发生,比如使用定时轮询的方式,主动调用 performance.getEntries 或者 performance.getEntriesByName 来获取。
为了解决这个问题,在 Performance Timeline Level 2 中,除了扩展了 Performance 的基本定义之外,还增加了 PerformanceObserver 接口,于是最新的 Performance Timeline Level 2 标准中包括了如下三点:
-
扩展了 Performance 接口的基本定义
-
在 Web Workers 中暴露了 PerformanceEntry
-
增加了 PerformanceObserver 的支持
此时我们本篇文章的主角:PerformanceObserver 带着它自身的使命终于出现了。
二、介绍 PerformanceObserver
了解了 PerformanceObserver 出现的背景,接下来我们就重点了解下它的具体用法吧。
1、简介
PerformanceObserver 主要用于监测性能度量事件,在浏览器的性能时间轴记录新的 performanceEntry(详见下方介绍) 时会被通知。
通过使用 PerformanceObserver() 构造函数我们可以创建并返回一个新的 PerformanceObserver 对象,从而进行性能的监测。
也就是说,性能指标可以通过 window.performance 获取,但是获取什么时候的指标就可以通过 PerformanceObserver 构造函数生成的实例,在不同的时机拿到对应不同的值。
2、PerformanceEntry
a. 首先我们先看下 mdn 中对它的介绍:
意思大概是,在页面运行过程中我们可以通过 PerformanceEntry 实例持续获取性能数据,拿到粒度更细的流程的 performance 数据信息,也称为 performance metric。而 PerformanceEntry 可以通过 performance.getEntries() 获取到,打印一下大概如下:
可以看出打印出来的是一个数组,而数组中的每一项都是 PerformanceEntry 的实例。PerformanceEntry 可以理解为描述浏览器中某一个行为的性能指标,比如获取资源文件的性能,一次事件的性能,渲染页面的性能等等。
b. PerformanceEntry 实例
说起 PerformanceEntry 数组中的实例,主要包括这么几个:
PerformanceResourceTiming:该实例主要用于确定页面各个资源加载所花费的时间,比如获取css、js、img文件、http接口等资源请求花费的时间。通过看 entryType 字段可以看到对应的 entryType 是 resource。
PerformanceNavigationTiming:这个实例用于确定一个页面从开始加载到结束需要的时间。通过看 entryType 字段可以看到对应的 entryType 是 navigation。
PerformancePaintTiming:这个实例主要是获取页面刷新渲染过程中,第一个像素点呈现在页面上的时间(first paint),以及第一个 dom 元素呈现在页面上的时间(first contentful paint)。通过看 entryType 字段可以看到对应的 entryType 是 paint。
c. entryType
通过下方表格可以看出,entryType 主要有 6 种类型,分别对应 6 个 sybtype,其中就包含了上方我们列出的部分实例。
了解了 PerformanceEntry,接下来我们了解下 PerformanceObserver 具体有哪些方法。
3、方法
PerformanceObserver 主要有3个方法。
a. PerformanceObserver.observe():当传参中的性能指标在上方指定的 entryTypes 之中时,该性能指标的回调函数将会被调用并返回。
b. PerformanceObserver.disconnect():停止性能观察者回调接收到性能指标。
c. PerformanceObserver.takeRecords():返回存储在性能观察器中的性能指标的列表,并将其清空。
4、示例
接下来,我们就重点用 PerformanceObserver 的 observe() 这个方法,分别简单实现下性能优化方面比较常见的几个性能指标数据吧。
a. FP(first-paint),从页面加载开始到第一个像素绘制到屏幕上的时间,也可以把 FP 理解成白屏时间。
const entryHandler = (list) => { for (const entry of list.getEntries()) { if (entry.name === 'first-paint') { observer.disconnect() } console.log(entry) } } const observer = new PerformanceObserver(entryHandler) observer.observe({ type: 'paint', buffered: true })
通过以上代码可以得到 FP 的内容:
其中 startTime 就是我们要的绘制时间。
b. FCP(first-contentful-paint),从页面加载开始到所有页面内容在屏幕上完成渲染的时间。
const entryHandler = (list) => { for (const entry of list.getEntries()) { if (entry.name === 'first-contentful-paint') { observer.disconnect() } console.log(entry) } } const observer = new PerformanceObserver(entryHandler) observer.observe({ type: 'paint', buffered: true })通过以上代码可以得到 FCP 的内容:
其中 startTime 就是我们要的绘制时间。
c. LCP(largest-contentful-paint),从页面加载开始到最大文本块或图像元素在屏幕上完成渲染的时间。LCP 指标会根据页面首次开始加载的时间点来报告可视区域内可见的最大图像或文本块完成渲染的相对时间。
const entryHandler = (list) => { if (observer) { observer.disconnect() } for (const entry of list.getEntries()) { console.log(entry) } } const observer = new PerformanceObserver(entryHandler) observer.observe({ type: 'largest-contentful-paint', buffered: true })
通过以上代码可以得到 LCP 的内容:
其中 startTime 就是我们要的绘制时间。element 是指 LCP 绘制的 DOM 元素。
通过监测用户访问页面的这些性能数据,可以直观的看到在哪些方面我们需要进行性能提升,从而可以根据不同页面的展现情况针对性的提高用户体验。
5、兼容性
了解了 PerformanceObserver 的具体做法,紧接着我们看下它目前的兼容性吧。
从表中我们可以看出,PerformanceObserver 的兼容性其实已经覆盖大部分浏览器了。对于比如 IE 或者移动端部分不兼容的浏览器,可以考虑使用我们下方介绍的观察者 Observer 中的 MutationObserver 进行代替。
而 MutationObserver 又是什么呢,接下来我们再简单介绍下。
6、MutationObserver
MutationObserver 在监听的 DOM 元素属性发生变化时会触发事件,与 PerformanceObserver 相同,也是一个观察者 API。
接下来我们通过 MutationObserver 简单实现下获取 FCP 首屏渲染时间。
const next = window.requestAnimationFrame ? requestAnimationFrame : setTimeout const ignoreDOMList = ['STYLE', 'SCRIPT', 'LINK'] observer = new MutationObserver(mutationList => { const entry = { children: [], } for (const mutation of mutationList) { if (mutation.addedNodes.length && isInScreen(mutation.target)) { // ... } } if (entry.children.length) { entries.push(entry) next(() => { entry.startTime = performance.now() }) } }) observer.observe(document, { childList: true, subtree: true, })
具体思路大致如下
(1)利用 MutationObserver 监听 document 对象,每当 DOM 元素属性发生变更时,触发事件。
(2)判断该 DOM 元素是否在首屏内,如果在,则在 requestAnimationFrame() 回调函数中调用 performance.now() 获取当前时间,作为它的绘制时间。
(3)将最后一个 DOM 元素的绘制时间和首屏中所有加载的图片时间作对比,将最大值作为首屏渲染时间。
这样就通过 MutationObserver 简单获取了首屏时间。
总结
至此,我们的 PerformanceObserver 就基本介绍完成了。PerformanceObserver 这个 API 涉及的内容挺多,本篇文章就针对以下几个内容简单介绍了下:
1、平时我们页面的性能指标数据可以通过 window.performance 获取,但是获取的时机就可以通过 PerformanceObserver 进行监测获取到对应指标。
2、我们可以通过 PerformanceEntry 实例持续获取性能数据,拿到粒度更细的流程的 performance 数据信息。
3、使用 PerformanceObserver 提供的方法 observe() 方法简单实现了 FP、FCP、LCP 指标数据的获取。
4、最后我们简单实现了通过 MutationObserver 获取 FCP 数据。
参考链接
https://developer.mozilla.org/zh-CN/docs/Web/API/Performance_Timeline
https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceObserver
https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceEntry/entryType
https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceNavigationTiming
https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
Google网站核心指标Core web vitals(LCP、FID、CLS)是什么
标签:const,observer,PerformanceObserver,paint,聊聊,entry,页面 From: https://www.cnblogs.com/momo798/p/16810097.html