自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

瀏覽器的五種 Observer,你用過幾種?

系統(tǒng) 瀏覽器
瀏覽器提供了 5 種 Observer 來監(jiān)聽這些變動(dòng):MutationObserver、IntersectionObserver、PerformanceObserver、ResizeObserver、ReportingObserver。

網(wǎng)頁開發(fā)中我們經(jīng)常要處理用戶交互,我們會(huì)用 addEventListener 添加事件監(jiān)聽器來監(jiān)聽各種用戶操作,比如 click、mousedown、mousemove、input 等,這些都是由用戶直接觸發(fā)的事件。

那么對(duì)于一些不是由用戶直接觸發(fā)的事件呢?比如元素從不可見到可見、元素大小的改變、元素的屬性和子節(jié)點(diǎn)的修改等,這類事件如何監(jiān)聽呢?

瀏覽器提供了 5 種 Observer 來監(jiān)聽這些變動(dòng):MutationObserver、IntersectionObserver、PerformanceObserver、ResizeObserver、ReportingObserver。

我們分別來看一下:

IntersectionObserver

一個(gè)元素從不可見到可見,從可見到不可見,這種變化如何監(jiān)聽呢?

用 IntersectionObserver。

IntersectionObserver 可以監(jiān)聽一個(gè)元素和可視區(qū)域相交部分的比例,然后在可視比例達(dá)到某個(gè)閾值的時(shí)候觸發(fā)回調(diào)。

我們準(zhǔn)備兩個(gè)元素:

<div id="box1">BOX111</div>
<div id="box2">BOX222</div>

加上樣式:

#box1,#box2 {
width: 100px;
height: 100px;
background: blue;
color: #fff;

position: relative;
}
#box1 {
top: 500px;
}
#box2 {
top: 800px;
}

這兩個(gè)元素分別在 500 和 800 px 的高度,我們監(jiān)聽它們的可見性的改變。

const intersectionObserver = new IntersectionObserver(
function (entries) {
console.log('info:');
entries.forEach(item => {
console.log(item.target, item.intersectionRatio)
})
}, {
threshold: [0.5, 1]
});

intersectionObserver.observe( document.querySelector('#box1'));
intersectionObserver.observe( document.querySelector('#box2'));

創(chuàng)建一個(gè) IntersectionObserver 對(duì)象,監(jiān)聽 box1 和 box2 兩個(gè)元素,當(dāng)可見比例達(dá)到 0.5 和 1 的時(shí)候觸發(fā)回調(diào)。

瀏覽器跑一下:

可以看到元素 box1 和 box2 在可視范圍達(dá)到一半(0.5)和全部(1)的時(shí)候分別觸發(fā)了回調(diào)。

這有啥用?

這太有用了,我們?cè)谧鲆恍?shù)據(jù)采集的時(shí)候,希望知道某個(gè)元素是否是可見的,什么時(shí)候可見的,就可以用這個(gè) api 來監(jiān)聽,還有做圖片的懶加載的時(shí)候,可以當(dāng)可視比例達(dá)到某個(gè)比例再觸發(fā)加載。

除了可以監(jiān)聽元素可見性,還可以監(jiān)聽元素的屬性和子節(jié)點(diǎn)的改變:

MutationObserver

監(jiān)聽一個(gè)普通 JS 對(duì)象的變化,我們會(huì)用 Object.defineProperty 或者 Proxy:

而監(jiān)聽元素的屬性和子節(jié)點(diǎn)的變化,我們可以用 MutationObserver:

MutationObserver 可以監(jiān)聽對(duì)元素的屬性的修改、對(duì)它的子節(jié)點(diǎn)的增刪改。

我們準(zhǔn)備這樣一個(gè)盒子:

<div id="box"><button>光</button></div>

加上樣式:

 #box {
width: 100px;
height: 100px;
background: blue;

position: relative;
}

就是這樣的:

我們定時(shí)對(duì)它做下修改:

setTimeout(() => {
box.style.background = 'red';
},2000);

setTimeout(() => {
const dom = document.createElement('button');
dom.textContent = '東東東';
box.appendChild(dom);
},3000);

setTimeout(() => {
document.querySelectorAll('button')[0].remove();
},5000);

2s 的時(shí)候修改背景顏色為紅色,3s 的時(shí)候添加一個(gè) button 的子元素,5s 的時(shí)候刪除第一個(gè) button。

然后監(jiān)聽它的變化:

const mutationObserver = new MutationObserver((mutationsList) => {
console.log(mutationsList)
});

mutationObserver.observe(box, {
attributes: true,
childList: true
});

創(chuàng)建一個(gè) MutationObserver 對(duì)象,監(jiān)聽這個(gè)盒子的屬性和子節(jié)點(diǎn)的變化。

瀏覽器跑一下:

可以看到在三次變化的時(shí)候都監(jiān)聽到了并打印了一些信息:

第一次改變的是 attributes,屬性是 style:

第二次改變的是 childList,添加了一個(gè)節(jié)點(diǎn):

第三次也是改變的 childList,刪除了一個(gè)節(jié)點(diǎn):

都監(jiān)聽到了!

這個(gè)可以用來做什么呢?比如文章水印被人通過 devtools 去掉了,那么就可以通過 MutationObserver 監(jiān)聽這個(gè)變化,然后重新加上,讓水印去不掉。

當(dāng)然,還有很多別的用途,這里只是介紹功能。

除了監(jiān)聽元素的可見性、屬性和子節(jié)點(diǎn)的變化,還可以監(jiān)聽大小變化:

ResizeObserver

窗口我們可以用 addEventListener 監(jiān)聽 resize 事件,那元素呢?

元素可以用 ResizeObserver 監(jiān)聽大小的改變,當(dāng) width、height 被修改時(shí)會(huì)觸發(fā)回調(diào)。

我們準(zhǔn)備這樣一個(gè)元素:

<div id="box"></div>

添加樣式:

#box {
width: 100px;
height: 100px;
background: blue;
}

在 2s 的時(shí)候修改它的高度:

const box = document.querySelector('#box');

setTimeout(() => {
box.style.width = '200px';
}, 3000);

然后我們用 ResizeObserver 監(jiān)聽它的變化:

const resizeObserver = new ResizeObserver(entries => {
console.log('當(dāng)前大小', entries)
});
resizeObserver.observe(box);

在瀏覽器跑一下:

大小變化被監(jiān)聽到了,看下打印的信息:

可以拿到元素和它的位置、尺寸。

這樣我們就實(shí)現(xiàn)了對(duì)元素的 resize 的監(jiān)聽。

除了元素的大小、可見性、屬性子節(jié)點(diǎn)等變化的監(jiān)聽外,還支持對(duì) performance 錄制行為的監(jiān)聽:

PerformanceObserver

瀏覽器提供了 performance 的 api 用于記錄一些時(shí)間點(diǎn)、某個(gè)時(shí)間段、資源加載的耗時(shí)等。

我們希望記錄了 performance 那就馬上上報(bào),可是怎么知道啥時(shí)候會(huì)記錄 performance 數(shù)據(jù)呢?

用 PeformanceObserver。

PerformanceObserver 用于監(jiān)聽記錄 performance 數(shù)據(jù)的行為,一旦記錄了就會(huì)觸發(fā)回調(diào),這樣我們就可以在回調(diào)里把這些數(shù)據(jù)上報(bào)。

比如 performance 可以用 mark 方法記錄某個(gè)時(shí)間點(diǎn):

performance.mark('registered-observer');

用 measure 方法記錄某個(gè)時(shí)間段:

performance.measure('button clicked', 'from', 'to');

后兩個(gè)個(gè)參數(shù)是時(shí)間點(diǎn),不傳代表從開始到現(xiàn)在。

我們可以用 PerformanceObserver 監(jiān)聽它們:

<html>
<body>
<button onclick="measureClick()">Measure</button>

<img src="https://p9-passport.byteacctimg.com/img/user-avatar/4e9e751e2b32fb8afbbf559a296ccbf2~300x300.image" />

<script>
const performanceObserver = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
console.log(entry);// 上報(bào)
})
});
performanceObserver.observe({entryTypes: ['resource', 'mark', 'measure']});

performance.mark('registered-observer');

function measureClick() {
performance.measure('button clicked');
}
</script>
</body>
</html>

創(chuàng)建 PerformanceObserver 對(duì)象,監(jiān)聽 mark(時(shí)間點(diǎn))、measure(時(shí)間段)、resource(資源加載耗時(shí)) 這三種記錄時(shí)間的行為。

然后我們用 mark 記錄了某個(gè)時(shí)間點(diǎn),點(diǎn)擊 button 的時(shí)候用 measure 記錄了某個(gè)時(shí)間段的數(shù)據(jù),還加載了一個(gè)圖片。

當(dāng)這些記錄行為發(fā)生的時(shí)候,希望能觸發(fā)回調(diào),在里面可以上報(bào)。

我們?cè)跒g覽器跑一下試試:

可以看到 mark 的時(shí)間點(diǎn)記錄、資源加載的耗時(shí)、點(diǎn)擊按鈕的 measure 時(shí)間段記錄都監(jiān)聽到了。

分別打印了這三種記錄行為的數(shù)據(jù):

mark:

圖片加載:

measure:

用了這些數(shù)據(jù),就可以上報(bào)上去做性能分析了。

除了元素、performance 外,瀏覽器還有一個(gè) reporting 的監(jiān)聽:

ReportingObserver

當(dāng)瀏覽器運(yùn)行到過時(shí)(deprecation)的 api 的時(shí)候,會(huì)在控制臺(tái)打印一個(gè)過時(shí)的報(bào)告:

瀏覽器還會(huì)在一些情況下對(duì)網(wǎng)頁行為做一些干預(yù)(intervention),比如會(huì)把占用 cpu 太多的廣告的 iframe 刪掉:

會(huì)在網(wǎng)絡(luò)比較慢的時(shí)候把圖片替換為占位圖片,點(diǎn)擊才會(huì)加載:

這些干預(yù)都是瀏覽器做的,會(huì)在控制臺(tái)打印一個(gè)報(bào)告:

這些干預(yù)或者過時(shí)的 api 并不是報(bào)錯(cuò),所以不能用錯(cuò)誤監(jiān)聽的方式來拿到,但這些情況對(duì)網(wǎng)頁 app 來說可能也是很重要的:

比如我這個(gè)網(wǎng)頁就是為了展示廣告的,但瀏覽器一干預(yù)給我把廣告刪掉了,我卻不知道。如果我知道的話或許可以優(yōu)化下 iframe。

比如我這個(gè)網(wǎng)頁的圖片很重要,結(jié)果瀏覽器一干預(yù)給我換成占位圖了,我卻不知道。如果我知道的話可能會(huì)優(yōu)化下圖片大小。

所以自然也要監(jiān)聽,所以瀏覽器提供了 ReportingObserver 的 api 用來監(jiān)聽這些報(bào)告的打印,我們可以拿到這些報(bào)告然后上傳。

const reportingObserver = new ReportingObserver((reports, observer) => {
for (const report of reports) {
console.log(report.body);//上報(bào)
}
}, {types: ['intervention', 'deprecation']});

reportingObserver.observe();

ReportingObserver 可以監(jiān)聽過時(shí)的 api、瀏覽器干預(yù)等報(bào)告等的打印,在回調(diào)里上報(bào),這些是錯(cuò)誤監(jiān)聽無法監(jiān)聽到但對(duì)了解網(wǎng)頁運(yùn)行情況很有用的數(shù)據(jù)。

文中的代碼上傳到了 github:https://github.com/QuarkGluonPlasma/browser-api-exercize

總結(jié)

監(jiān)聽用戶的交互行為,我們會(huì)用 addEventListener 來監(jiān)聽 click、mousedown、keydown、input 等事件,但對(duì)于元素的變化、performance 的記錄、瀏覽器干預(yù)行為這些不是用戶交互的事件就要用 XxxObserver 的 api 了。

瀏覽器提供了這 5 種 Observer:

  • IntersectionObserver:監(jiān)聽元素可見性變化,常用來做元素顯示的數(shù)據(jù)采集、圖片的懶加載
  • MutationObserver:監(jiān)聽元素屬性和子節(jié)點(diǎn)變化,比如可以用來做去不掉的水印
  • ResizeObserver:監(jiān)聽元素大小變化
  • 還有兩個(gè)與元素?zé)o關(guān)的:
  • PerformanceObserver:監(jiān)聽 performance 記錄的行為,來上報(bào)數(shù)據(jù)
  • ReportingObserver:監(jiān)聽過時(shí)的 api、瀏覽器的一些干預(yù)行為的報(bào)告,可以讓我們更全面的了解網(wǎng)頁 app 的運(yùn)行情況

這些 api 相比 addEventListener 添加的交互事件來說用的比較少,但是在特定場(chǎng)景下都是很有用的。

瀏覽器的 5 種 Observer,你用過幾種呢?在什么情況下用到過呢?

責(zé)任編輯:姜華 來源: 神光的編程秘籍
相關(guān)推薦

2024-10-30 16:39:45

2019-07-22 13:39:59

Python編輯器開發(fā)

2022-03-28 20:57:31

私有屬性class屬性和方法

2021-12-15 23:10:34

JS Debugger 前端開發(fā)

2020-10-12 09:59:59

AndroidGoogle瀏覽器

2024-01-17 13:58:00

算法C#冒泡排序

2023-11-22 09:45:44

2021-03-03 00:01:30

Redis數(shù)據(jù)結(jié)雙向鏈表

2010-04-05 21:57:14

Netscape瀏覽器

2020-11-16 07:05:34

瀏覽器請(qǐng)求硬核

2019-04-30 10:00:59

CSS居中前端

2016-11-11 14:03:01

2011-04-25 11:05:10

javascript

2016-06-02 13:22:12

LinuxWeb瀏覽器

2024-03-20 08:06:20

瀏覽器擴(kuò)展插件iTab

2021-03-08 05:42:26

瀏覽器FirefoxVIA瀏覽器

2021-10-08 08:20:06

LinuxChromium瀏覽器

2016-01-05 12:54:52

瀏覽器瀏覽器端緩存

2023-04-08 11:06:23

Firefox瀏覽器

2012-03-20 11:41:18

海豚瀏覽器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)