We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前段时间在研究前端异常监控/埋点平台的实现。
在思考方案时,想到了浏览器自带的观察者以及页面生命周期API 。
于是在翻查资料时意外发现,原来现代浏览器支持多达四种不同类型的观察者:
Intersection Observer
Mutation Observer
Resize Observer
Performance Observer
IntersectionObserver
IntersectionObserver接口,提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法,祖先元素与视窗(viewport)被称为根(root)
viewport
viewport)
root
想要计算Web页面的元素的位置,非常依赖于DOM状态的显式查询。但这些查询是同步的,会导致昂贵的样式计算开销(重绘和回流),且不停轮询会导致大量的性能浪费。
DOM
于是便发展了以下的几种方案:
scroll
而它们都有几项共同特点:
web
Intersection Observer API通过为开发人员提供一种新方法来异步查询元素相对于其他元素或全局视口的位置,从而解决了上述问题:
Intersection Observer API
CPU
GPU
使用IntersectionObserver API主要需要三个步骤:
IntersectionObserver API
const options = { root: document.querySelector('.scrollContainer'), rootMargin: '0px', threshold: [0.3, 0.5, 0.8, 1] } const observer = new IntersectionObserver(handler, options)
这几个参数用大白话解释就是:
rootMargin
threshold
[0.3]
当目标元素与根元素通过阈值相交时,就会触发回调函数。
function handler (entries, observer) { entries.forEach(entry => { // 每个成员都是一个IntersectionObserverEntry对象。 // 举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。 // entry.boundingClientRect // entry.intersectionRatio // entry.intersectionRect // entry.isIntersecting // entry.rootBounds // entry.target // entry.time }); }
任何目标元素都可以通过调用.observer(target)方法来观察。
.observer(target)
const target = document.querySelector(“.targetBox”); observer.observe(target);
此外,还有两个方法:
停止对某目标的监听
observer.unobserve(target)
终止对所有目标的监听
observer.disconnect()
HTML:
HTML
<img src="placeholder.png" data-src="img-1.jpg"> <img src="placeholder.png" data-src="img-2.jpg"> <img src="placeholder.png" data-src="img-3.jpg"> <!-- more images -->
脚本:
let observer = new IntersectionObserver( (entries, observer) => { entries.forEach(entry => { /* 替换属性 */ entry.target.src = entry.target.dataset.src; observer.unobserve(entry.target); }); }, {rootMargin: "0px 0px -200px 0px"}); document.querySelectorAll('img').forEach(img => { observer.observe(img) });
上述例子表示 仅在到达视口距离底部200px视加载图片。
关于兴趣埋点,一个比较通用的方案是:
来自:《超好用的API之IntersectionObserver》
const boxList = [...document.querySelectorAll('.box')] var io = new IntersectionObserver((entries) =>{ entries.forEach(item => { // intersectionRatio === 1说明该元素完全暴露出来,符合业务需求 if (item.intersectionRatio === 1) { // 。。。 埋点曝光代码 io.unobserve(item.target) } }) }, { root: null, threshold: 1, // 阀值设为1,当只有比例达到1时才触发回调函数 }) // observe遍历监听所有box节点 boxList.forEach(box => io.observe(box))
至于怎样评断用户是否感兴趣,记录方式就见仁见智了:
PC
touch
这里就不展开写了(我懒)。
这里提供控制视频的版本
<video src="OSRO-animation.mp4" controls=""></video>
js:
js
let video = document.querySelector('video'); let isPaused = false; /* Flag for auto-paused video */ let observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if(entry.intersectionRatio!=1 && !video.paused){ video.pause(); isPaused = true; } else if(isPaused) {video.play(); isPaused=false} }); }, {threshold: 1}); observer.observe(video);
效果:
接口提供了监视对DOM树所做更改的能力。它被设计为旧的MutationEvents功能的替代品,该功能是DOM3 Events规范的一部分。
MutationEvents
DOM3 Events
归根究底,是MutationEvents的功能不尽人意:
MDN
DOM Event
mutation
来自:《监听DOM加载完成及改变——MutationObserver应用》
MutationEvents的原理:通过绑定事件监听DOM
乍一看到感觉很正常,那列一下相关监听的事件:
DOMAttributeNameChanged DOMCharacterDataModified DOMElementNameChanged DOMNodeInserted DOMNodeInsertedIntoDocument DOMNodeRemoved DOMNodeRemovedFromDocument DOMSubtreeModified
甭记,这么多事件,各内核各版本浏览器想兼容怕是要天荒地老。
MutationObserver
而Mutation Observer的优势在于:
简单讲:异步万岁!
异步万岁
使用MutationObserver API主要需要三个步骤:
MutationObserver API
let observer = new MutationObserver(callback);
上面代码中的回调函数,会在每次 DOM 变动后调用。该回调函数接受两个参数,第一个是变动数组,第二个是观察器实例,下面是一个例子:
function callback (mutations, observer) { mutations.forEach(function(mutation) { console.log(mutation); }); });
其中每个mutation都对应一个MutationRecord对象,记录着DOM每次发生变化的变动记录
MutationRecord
MutationRecord对象包含了DOM的相关信息,有如下属性:
type
attribute
characterData
childList
target
addedNodes
removedNodes
previousSibling
null
nextSibling
attributeName
attributeFilter
oldValue
MutationObserver.observe(dom, options)
启动监听,接收两个参数。
options
mutationObserver.observe(content, { attributes: true, // Boolean - 观察目标属性的改变 characterData: true, // Boolean - 观察目标数据的改变(改变前的数据/值) childList: true, // Boolean - 观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化 subtree: true, // Boolean - 目标以及目标的后代改变都会观察 attributeOldValue: true, // Boolean - 表示需要记录改变前的目标属性值 characterDataOldValue: true, // Boolean - 设置了characterDataOldValue可以省略characterData设置 // attributeFilter: ['src', 'class'] // Array - 观察指定属性 });
优先级 :
attributeFilter/attributeOldValue
attributes
characterDataOldValue
attributes/characterData/childList
true
停止观察。调用后不再触发观察器,解除订阅
MutationObserver.disconnect()
清除变动记录。即不再处理未处理的变动。该方法返回变动记录的数组,注意,该方法立即生效。
MutationObserver.takeRecords()
基本使用是:
const target = document.getElementById('target-id') const observer = new MutationObserver(records => { // 输入变更记录 }) // 开始观察 observer.observe(target, { characterData: true })
这里可以有几种处理。
#
有个Vue的小型插件就是这么实现的:
Vue
来自:《vue-hashtag-textarea》
这个实现也是秀得飞起:
Hacking the color picker game — MutationObserver
游戏的逻辑很简单,当中间的色块颜色改变时,在时间限制内于底下的选项选择跟它颜色一样的选项就得分。难的点在于越后面的关卡选项越多,而且选项颜色也越相近,例如:
其实原理非常简单,就是观察色块的backgroundColor(属性变化attributes),然后触发点击事件e.click()。
backgroundColor
e.click()
var targetNode = document.querySelector('#kolor-kolor'); var config = { attributes: true }; var callback = function(mutationsList, observer) { if (mutationsList[0].type == 'attributes') { console.log('attribute change!'); let ans = document.querySelector('#kolor-kolor').style.backgroundColor; document.querySelectorAll('#kolor-options a').forEach( (e) => { if (e.style.backgroundColor == ans) { e.text = 'Ans!'; e.click() } }) } }; var observer = new MutationObserver(callback); observer.observe(targetNode, config);
ResizeObserver
ResizeObserver API是一个新的JavaScript API,与IntersectionObserver API非常相似,它们都允许我们去监听某个元素的变化。
ResizeObserver API
JavaScript API
开发过程当中经常遇到的一个问题就是如何监听一个 div 的尺寸变化。
div
但众所周知,为了监听 div 的尺寸变化,都将侦听器附加到 window 中的 resize 事件。
window
resize
但这很容易导致性能问题,因为大量的触发事件。
换句话说,使用 window.resize 通常是浪费的,因为它告诉我们每个视窗大小的变化,而不仅仅是当一个元素的大小发生变化。
window.resize
而且resize事件会在一秒内触发将近60次,很容易在改变窗口大小时导致性能问题
比如说,你要调整一个元素的大小,那就需要在 resize 的回调函数 callback() 中调用 getBoundingClientRect 或 getComputerStyle。不过你要是不小心处理所有的读和写操作,就会导致布局混乱。比如下面这个小示例:
callback()
getBoundingClientRect
getComputerStyle
ResizeObserver API 的核心优势有两点:
使用ResizeObserver API同样也是三个步骤:
let observer = new ResizeObserver(callback);
const callback = entries => { entries.forEach(entry => { }) }
每一个entry都是一个对象,包含两个属性contentRect和target
entry
contentRect
contentRect都是一些位置信息:
bottom
top + height
height
padding
border
left
padding-left
right
left + width
top
padidng-top
width
x
y
observer.observe(document.body)
unobserve方法:取消单节点观察
unobserve
observer.unobserve(document.body)
disconnect方法:取消所有节点观察
disconnect
observer.disconnect(document.body)
html:
html
<div class="box"> <h3 class="info"></h3> </div> <div class="box small"> <h3 class="info"></h3> </div>
添加点样式:
body { width: 100vw; height: 100vh; display: flex; flex-direction: column; justify-content: center; padding: 2vw; box-sizing: border-box; } .box { text-align: center; height: 20vh; border-radius: 8px; box-shadow: 0 0 4px rgba(0,0,0,.25); display: flex; justify-content: center; align-items: center; padding: 1vw } .box h3 { color: #fff; margin: 0; font-size: 5vmin; text-shadow: 0 0 10px rgba(0,0,0,0.4); } .box.small { max-width: 550px; margin: 1rem auto; }
JavaScript代码:
JavaScript
const boxes = document.querySelectorAll('.box'); let callbackFired = 0; const myObserver = new ResizeObserver(entries => { for (let entry of entries) { callbackFired++ const infoEl = entry.target.querySelector('.info'); const width = Math.floor(entry.contentRect.width); const height = Math.floor(entry.contentRect.height); const angle = Math.floor(width / 360 * 100); const gradient = `linear-gradient(${ angle }deg, rgba(0,143,104,1) 50%, rgba(250,224,66,1) 50%)`; entry.target.style.background = gradient; infoEl.innerText = ` I'm ${ width }px and ${ height }px tall Callback fired: ${callbackFired} `; } }); boxes.forEach(box => { myObserver.observe(box); });
当你拖动浏览器窗口,改变其大小时,看到的效果如下:
简单的@media就可以实现:
@media
@media only screen and (max-width: 576px) { .post__item { flex-direction: column; } .post__image { flex: 0 auto; height: auto; } }
@media查询的最大问题是:
以下是指令版实现:
使用:
这是vue-responsive-components库的具体实现代码,还有组件形式的实现,感兴趣的可以去看看。
vue-responsive-components
PerformanceObserver
这是一个浏览器和Node.js 里都存在的API,采用相同W3C的Performance Timeline规范
Node.js
W3C
Performance Timeline
window.performance
window.PerformanceObserver
perf_hooks
const { PerformanceObserver, performance } = require('perf_hooks');
首先来看Performance 接口:
Performance
可以获取到当前页面中与性能相关的信息。它是 High Resolution Time API 的一部分,同时也融合了 Performance Timeline API、Navigation Timing AP、 User Timing API 和 Resource Timing API。
High Resolution Time API
Performance Timeline API
Navigation Timing AP
User Timing API
Resource Timing API
Performance API 是大家熟悉的一个接口,他记录着几种性能指数的庞大对象集合。
Performance API
performance.getEntries
performance.getEntriesByName
performance.now
为了解决上述的问题,在Performance Timeline Level 2中,除了扩展了Performance的基本定义以外,还增加了PerformanceObserver接口。
Performance Timeline Level 2
PerformanceObserver是浏览器内部对Performance实现的观察者模式,也是现代浏览器支持的几个 Observer 之一。
Observer
来自:《你了解 Performance Timeline Level 2 吗?》
它解决了以下3点问题:
timeline
W3C官网文档鼓励开发人员尽可能使用PerformanceObserver,而不是通过Performance获取性能参数及指标。
使用PerformanceObserver API主要需要三个步骤:
PerformanceObserver API
let observer = new PerformanceObserver(callback);
const callback = (list, observer) => { const entries = list.getEntries(); entries.forEach((entry) => { console.log(“Name: “ + entry.name + “, Type: “ + entry.entryType + “, Start: “ + entry.startTime + “, Duration: “ + entry.duration + “\n”); }); }
其中每一个list都是一个完整的PerformanceObserverEntryList对象: 包含三个方法getEntries、getEntriesByType、getEntriesByName:
list
PerformanceObserverEntryList
getEntries
getEntriesByType
getEntriesByName
observer.observe({entryTypes: ["entryTypes"]});
observer.observe(...)方法接受可以观察到的有效的入口类型。这些输入类型可能属于各种性能API,比如User tming或Navigation Timing API。有效的entryType值:
observer.observe(...)
User tming
Navigation Timing API
entryType
来自:《资源监控》
function filterTime(a, b) { return (a > 0 && b > 0 && (a - b) >= 0) ? (a - b) : undefined; } let resolvePerformanceTiming = (timing) => { let o = { initiatorType: timing.initiatorType, name: timing.name, duration: parseInt(timing.duration), redirect: filterTime(timing.redirectEnd, timing.redirectStart), // 重定向 dns: filterTime(timing.domainLookupEnd, timing.domainLookupStart), // DNS解析 connect: filterTime(timing.connectEnd, timing.connectStart), // TCP建连 network: filterTime(timing.connectEnd, timing.startTime), // 网络总耗时 send: filterTime(timing.responseStart, timing.requestStart), // 发送开始到接受第一个返回 receive: filterTime(timing.responseEnd, timing.responseStart), // 接收总时间 request: filterTime(timing.responseEnd, timing.requestStart), // 总时间 ttfb: filterTime(timing.responseStart, timing.requestStart), // 首字节时间 }; return o; }; let resolveEntries = (entries) => entries.map(item => resolvePerformanceTiming(item)); let resources = { init: (cb) => { let performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance; if (!performance || !performance.getEntries) { return void 0; } if (window.PerformanceObserver) { let observer = new window.PerformanceObserver((list) => { try { let entries = list.getEntries(); cb(resolveEntries(entries)); } catch (e) { console.error(e); } }); observer.observe({ entryTypes: ['resource'] }) } else { window.addEventListener('load', () => { let entries = performance.getEntriesByType('resource'); cb(resolveEntries(entries)); }); } }, };
参考文章有点多:
资源监控 Media Queries Based on Element Width with MutationObserver 以用户为中心的性能指标 A Few Functional Uses for Intersection Observer to Know When an Element is in View Getting To Know The MutationObserver API Different Types Of Observers Supported By Modern Browsers THE RESIZE OBSERVER EXPLAINED A Look at the Resize Observer JavaScript API 这四个观察者,都非常适合集成到监控系统。
且都有对应的Polyfills版实现。
Polyfills
网上的总结和文档都深浅不一,如果哪里有错误,欢迎指正。
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:
也可以来我的GitHub博客里拿所有文章的源文件:
GitHub
前端劝退指南:https://github.com/roger-hiro/BlogFN
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
前段时间在研究前端异常监控/埋点平台的实现。
在思考方案时,想到了浏览器自带的观察者以及页面生命周期API 。
于是在翻查资料时意外发现,原来现代浏览器支持多达四种不同类型的观察者:
Intersection Observer
,交叉观察者。Mutation Observer
,变动观察者。Resize Observer
,视图观察者。Performance Observer
,性能观察者disconnect()
takeRecords()
disconnect()
takeRecords()
unobserve()
disconnect()
unobserve()
disconnect()
takeRecords()
Scroll 和 Resize 事件
2. 图片懒加载
3. 兴趣埋点
4. 控制动画/视频执行(性能优化)
2. 实现视觉差滚动
3. 图片预加载
4. 实现富文本编辑器
2. 响应式组件
2. 分析性能对业务的影响(交互快/慢是否会影响销量)
1.
IntersectionObserver
:交叉观察者1. 出现的意义
想要计算Web页面的元素的位置,非常依赖于
DOM
状态的显式查询。但这些查询是同步的,会导致昂贵的样式计算开销(重绘和回流),且不停轮询会导致大量的性能浪费。于是便发展了以下的几种方案:
scroll
等事件或通过插件的形式,计算真实元素可见性。而它们都有几项共同特点:
web
平台支持匮乏,各有各家的处理。需要开发人员消耗大量精力兼容。2.
IntersectionObserver
的优势Intersection Observer API
通过为开发人员提供一种新方法来异步查询元素相对于其他元素或全局视口的位置,从而解决了上述问题:DOM
和样式查询,连续轮询以及使用自定义插件的需求。CPU
,GPU
和资源成本。3.
IntersectionObserver
基本使用使用
IntersectionObserver API
主要需要三个步骤:1.创建观察者
这几个参数用大白话解释就是:
root
:指定一个根元素rootMargin
:使用类似于设置CSS边距的语法来指定根边距(根元素的观察影响范围)threshold
:阈值,可以为数组。[0.3]
意味着,当目标元素在根元素指定的元素内可见30%时,调用处理函数。2. 定义回调事件
当目标元素与根元素通过阈值相交时,就会触发回调函数。
3. 定义要观察的目标对象
任何目标元素都可以通过调用
.observer(target)
方法来观察。此外,还有两个方法:
停止对某目标的监听
终止对所有目标的监听
4. 例子1:图片懒加载
HTML
:脚本:
上述例子表示 仅在到达视口距离底部200px视加载图片。
5. 例子2:兴趣埋点
关于兴趣埋点,一个比较通用的方案是:
至于怎样评断用户是否感兴趣,记录方式就见仁见智了:
PC
端记录鼠标点击次数/悬停时间,移动端记录touch
事件这里就不展开写了(我懒)。
6. 控制动画/视频 执行
这里提供控制视频的版本
HTML
:js
:效果:
2.
Mutation Observer
:变动观察者1. 出现的意义
归根究底,是
MutationEvents
的功能不尽人意:MDN
中也写到了,是被DOM Event
承认在API上有缺陷,反对使用。DOM
添加mutation
监听器极度降低进一步修改DOM
文档的性能(慢1.5 - 7倍),此外, 移除监听器不会逆转的损害。MutationEvents
的原理:通过绑定事件监听DOM
乍一看到感觉很正常,那列一下相关监听的事件:
甭记,这么多事件,各内核各版本浏览器想兼容怕是要天荒地老。
2.
MutationObserver
的优势而
Mutation Observer
的优势在于:MutationEvents
事件是同步触发,也就是说,DOM
的变动立刻会触发相应的事件;Mutation Observer
则是异步触发,DOM
的变动并不会马上触发,而是要等到当前所有DOM
操作都结束才触发。DOM
下子元素的变更记录简单讲:
异步万岁
!3.
MutationObserver
基本使用使用
MutationObserver API
主要需要三个步骤:1. 创建观察者
2. 定义回调函数
上面代码中的回调函数,会在每次 DOM 变动后调用。该回调函数接受两个参数,第一个是变动数组,第二个是观察器实例,下面是一个例子:
其中每个
mutation
都对应一个MutationRecord
对象,记录着DOM
每次发生变化的变动记录MutationRecord
对象包含了DOM的相关信息,有如下属性:type
attribute
、characterData
或者childList
)target
DOM
节点addedNodes
DOM
节点removedNodes
DOM
节点previousSibling
null
nextSibling
null
attributeName
attributeFilter
,则只返回预先指定的属性oldValue
attribute
和characterData
变动有效,如果发生childList
变动,则返回null
3. 定义要观察的目标对象
启动监听,接收两个参数。
DOM
节点。options
。优先级 :
attributeFilter/attributeOldValue
>attributes
characterDataOldValue
>characterData
attributes/characterData/childList
(或更高级特定项)至少有一项为true;true
此外,还有两个方法:
停止观察。调用后不再触发观察器,解除订阅
清除变动记录。即不再处理未处理的变动。该方法返回变动记录的数组,注意,该方法立即生效。
4. 例子1:
MutationObserver
监听文本变化基本使用是:
这里可以有几种处理。
#
”号时,启动搜索框预检文本或高亮话题。有个
Vue
的小型插件就是这么实现的:5. 例子2: 色块小游戏脚本
这个实现也是秀得飞起:
游戏的逻辑很简单,当中间的色块颜色改变时,在时间限制内于底下的选项选择跟它颜色一样的选项就得分。难的点在于越后面的关卡选项越多,而且选项颜色也越相近,例如:
其实原理非常简单,就是观察色块的
backgroundColor
(属性变化attributes
),然后触发点击事件e.click()
。3.
ResizeObserver
,视图观察者ResizeObserver API
是一个新的JavaScript API
,与IntersectionObserver API
非常相似,它们都允许我们去监听某个元素的变化。1. 出现的意义
开发过程当中经常遇到的一个问题就是如何监听一个
div
的尺寸变化。但众所周知,为了监听
div
的尺寸变化,都将侦听器附加到window
中的resize
事件。但这很容易导致性能问题,因为大量的触发事件。
换句话说,使用
window.resize
通常是浪费的,因为它告诉我们每个视窗大小的变化,而不仅仅是当一个元素的大小发生变化。而且
resize
事件会在一秒内触发将近60次,很容易在改变窗口大小时导致性能问题比如说,你要调整一个元素的大小,那就需要在
resize
的回调函数callback()
中调用getBoundingClientRect
或getComputerStyle
。不过你要是不小心处理所有的读和写操作,就会导致布局混乱。比如下面这个小示例:2.
ResizeObserver
的优势ResizeObserver API
的核心优势有两点:DOM
元素观察,而不是window
3.
ResizeObserver
基本使用使用
ResizeObserver API
同样也是三个步骤:1. 创建观察者
2. 定义回调函数
每一个
entry
都是一个对象,包含两个属性contentRect
和target
contentRect
都是一些位置信息:bottom
top + height
的值height
padding
,border
值left
padding-left
的值right
left + width
的值top
padidng-top
的值width
padding
,border
值x
top
相同y
left
相同3. 定义要观察的目标对象
unobserve
方法:取消单节点观察disconnect
方法:取消所有节点观察4. 例子1:缩放渐变背景
html
:添加点样式:
JavaScript
代码:当你拖动浏览器窗口,改变其大小时,看到的效果如下:
5. 例子2:响应式
Vue
组件简单的
@media
就可以实现:@media
查询的最大问题是:以下是指令版实现:
使用:
效果:
这是
vue-responsive-components
库的具体实现代码,还有组件形式的实现,感兴趣的可以去看看。4.
PerformanceObserver
:性能观察者这是一个浏览器和
Node.js
里都存在的API,采用相同W3C
的Performance Timeline
规范window.performance
和window.PerformanceObserver
。Node.js
程序中需要perf_hooks
取得性能对象,如下:1. 出现的意义
首先来看
Performance
接口:可以获取到当前页面中与性能相关的信息。它是
High Resolution Time API
的一部分,同时也融合了Performance Timeline API
、Navigation Timing AP
、User Timing API
和Resource Timing API
。Performance API
是大家熟悉的一个接口,他记录着几种性能指数的庞大对象集合。performance.getEntries
或者performance.getEntriesByName
来获得。performance.now
来计算。为了解决上述的问题,在
Performance Timeline Level 2
中,除了扩展了Performance
的基本定义以外,还增加了PerformanceObserver
接口。2.
PerformanceObserver
的优势PerformanceObserver
是浏览器内部对Performance
实现的观察者模式,也是现代浏览器支持的几个Observer
之一。它解决了以下3点问题:
timeline
获取记录。W3C
官网文档鼓励开发人员尽可能使用PerformanceObserver
,而不是通过Performance
获取性能参数及指标。3.
PerformanceObserver
的使用使用
PerformanceObserver API
主要需要三个步骤:1. 创建观察者
2. 定义回调函数事件
其中每一个
list
都是一个完整的PerformanceObserverEntryList
对象:包含三个方法
getEntries
、getEntriesByType
、getEntriesByName
:3. 定义要观察的目标对象
observer.observe(...)
方法接受可以观察到的有效的入口类型。这些输入类型可能属于各种性能API,比如User tming
或Navigation Timing API
。有效的entryType
值:4. 例子1:静态资源监控
参考文章&总结
参考文章有点多:
且都有对应的
Polyfills
版实现。网上的总结和文档都深浅不一,如果哪里有错误,欢迎指正。
❤️ 看完三件事
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:
也可以来我的
GitHub
博客里拿所有文章的源文件:前端劝退指南:https://github.com/roger-hiro/BlogFN
The text was updated successfully, but these errors were encountered: