一起認(rèn)識(shí)下瀏覽器的 5 種觀察器 API

來(lái)源:大轉(zhuǎn)轉(zhuǎn)FE

“圖片懶加載”,這個(gè)詞語(yǔ)想必大家再熟悉不過(guò)了。傳統(tǒng)的實(shí)現(xiàn)方法是,監(jiān)聽(tīng)scroll事件,獲取img元素相對(duì)于視口的頂點(diǎn)位置el.getBoundingClientRect().top,只要這個(gè)值小于瀏覽器的高度window.innerHeight就說(shuō)明進(jìn)入可視區(qū)域,當(dāng)圖片進(jìn)入可視區(qū)域時(shí)再去加載圖片資源。

這種方法的缺點(diǎn)是,由于scroll事件密集發(fā)生,計(jì)算量很大,容易造成性能問(wèn)題。

目前瀏覽器API中的 IntersectionObserver 交叉觀察器,可自動(dòng)"觀察"目標(biāo)元素與根元素的交叉區(qū)域的變化,以此判斷元素是否可見(jiàn)。利用這個(gè)方法,在觀察到元素可見(jiàn)時(shí),再去加載圖片資源。這樣“圖片懶加載”實(shí)現(xiàn)起來(lái)就很容易了。

當(dāng)然瀏覽器的觀察器,不僅IntersectionObserver這一種。下面我們依次介紹下瀏覽器5種觀察器的基本用法,以及它們的應(yīng)用。

首先來(lái)看一下,什么是瀏覽器的觀察器?

一、什么是瀏覽器的觀察器?
針對(duì)一些不是由用戶直接觸發(fā)的事件,比如DOM元素從不可見(jiàn)到可見(jiàn)、DOM大小、屬性的改變和子節(jié)點(diǎn)個(gè)數(shù)的修改等,瀏覽器提供特定的api去監(jiān)控這些變化,這些api就是瀏覽器的觀察器。

二、瀏覽器的觀察器有哪些?
瀏覽器的觀察器共有 5 種 :IntersectionObserver(交叉觀察器)、MutationObserver(變化觀察器)、ResizeObserver(大小觀察器)、PerformanceObserver(性能觀察器)、ReportingObserver(報(bào)告觀察器) 。

2.1 IntersectionObserver 交叉觀察器
該觀察器自動(dòng)"觀察"目標(biāo)元素與根元素交叉區(qū)域的變化。默認(rèn)根元素為文檔視口,此時(shí)交叉區(qū)域的變化決定了用戶在當(dāng)前視口能否看到目標(biāo)元素,因此它經(jīng)常被用于“元素可見(jiàn)性”觀察。比如:圖片懶加載、無(wú)限滾動(dòng)、廣告曝光量統(tǒng)計(jì)等。



上圖中,目標(biāo)元素粉色方塊不僅會(huì)隨著窗口滾動(dòng),還會(huì)在容器Box1里面滾動(dòng),目標(biāo)元素與視口(或指定的根元素)產(chǎn)生的交叉區(qū)域會(huì)不斷變化。我們將這個(gè)交叉區(qū)域占目標(biāo)元素的比例,稱為目標(biāo)元素的交叉比例intersectionRatio。

注意:根元素為視口時(shí)(左圖),交叉比例大于0,即元素可見(jiàn),交叉比例等于0,即元素不可見(jiàn)。指定其他元素為根元素時(shí)(右圖),根元素必須是目標(biāo)元素的祖先節(jié)點(diǎn),此時(shí)交叉比例大于0不一定代表元素在當(dāng)前視口可見(jiàn)。

2.1.1 基本用法
通過(guò)new IntersectionObserver(callback[, options]) 創(chuàng)建觀察器實(shí)例 observer,并按照options配置,指定根元素root、根元素的外邊距rootMargin、執(zhí)行callback的交叉比例的閾值threshold。
let options = { //配置observer實(shí)例的對(duì)象
    // root: document.querySelector('#parentBox'), // 指定根元素,必須是目標(biāo)元素的父級(jí)元素; 默認(rèn):文檔視口
    // rootMargin: "0px 0px 0px 0px", //根元素的外邊距。類(lèi)似于 CSS 中的 margin 屬性。默認(rèn)值是"0px 0px 0px 0px",分別表示 top、right、bottom 和 left 四個(gè)方向的值,用來(lái)擴(kuò)展或縮小rootBounds這個(gè)矩形的大小,從而影響intersectionRect交叉區(qū)域的大小。
    threshold: [0] //目標(biāo)元素和根元素相交部分的比例達(dá)到該值的時(shí)候,callback 函數(shù)將會(huì)被執(zhí)行,eg: 1 、[0.5 , 1],當(dāng)為數(shù)組時(shí)每達(dá)到該值都會(huì)執(zhí)行 callback 函數(shù)。默認(rèn)值為[0]。
}
let observer = new IntersectionObserver(callback, options);
定義觀察到目標(biāo)元素與根元素交叉區(qū)域變化時(shí)的回調(diào)函數(shù)callback(entries, observer)。entries數(shù)組中,每個(gè)成員都是一個(gè)IntersectionObserverEntry對(duì)象,如果同時(shí)有兩個(gè)被觀察的對(duì)象的可見(jiàn)性發(fā)生變化,entries數(shù)組就會(huì)有兩個(gè)成員。一般會(huì)觸發(fā)兩次callback。一次是目標(biāo)元素剛剛進(jìn)入視口(開(kāi)始可見(jiàn)),另一次是完全離開(kāi)視口(開(kāi)始不可見(jiàn))。
let callback = (entries, observer) => {
    entries.forEach(entry => {
        consloe.log(entry) //包含目標(biāo)元素的信息的對(duì)象
        // entry.time:可見(jiàn)性發(fā)生變化的時(shí)間,是一個(gè)高精度時(shí)間戳,單位為毫秒
        // entry.target:被觀察的目標(biāo)元素,是一個(gè) DOM 節(jié)點(diǎn)對(duì)象
        // entry.rootBounds:根元素的矩形區(qū)域的信息,getBoundingClientRect()方法的返回值,如果沒(méi)有根元素(即直接相對(duì)于視口滾動(dòng)),則返回null
        // entry.boundingClientRect:目標(biāo)元素的矩形區(qū)域的信息
        // entry.intersectionRect:目標(biāo)元素與視口(或根元素)的交叉區(qū)域的信息
        // entry.intersectionRatio:根和目標(biāo)元素的交叉區(qū)域的比例值,即intersectionRect占boundingClientRect的比例,0 為完全不可見(jiàn),1 為完全可見(jiàn)
        // entry.isIntersecting:true表示從不可視狀態(tài)變?yōu)榭梢暊顟B(tài)。false表示從可視狀態(tài)到不可視狀態(tài):false
    });
};
observer.observe(targetNode) 指定目標(biāo)元素 targetNode1、targetNode2,開(kāi)始觀察。
//observe的參數(shù)是一個(gè) DOM 節(jié)點(diǎn)對(duì)象。如果要觀察多個(gè)節(jié)點(diǎn),就要多次調(diào)用這個(gè)方法。
observer.observe(targetNode1);
observer.observe(targetNode2); //開(kāi)始觀察目標(biāo)元素。
// observer.disconnect(); //關(guān)閉觀察器。
// observer.takeRecords(); //返回所有觀察目標(biāo)對(duì)象數(shù)組。
// observer.unobserve(targetNode1); //停止觀察特定目標(biāo)元素。
2.1.2 實(shí)例:圖片懶加載
創(chuàng)建交叉觀察器,通過(guò)observe為所有的圖片資源img開(kāi)啟了交叉觀察,當(dāng)某個(gè)圖片資源,從不可視狀態(tài)變?yōu)榭梢暊顟B(tài)時(shí),便添加圖片的src屬性,從而引發(fā)圖片資源的加載。

const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) { //true表示從不可視狀態(tài)變?yōu)榭梢暊顟B(tài)
            let img = entry.target;
            img.setAttribute('src', img.getAttribute('data-src'))
            observer.unobserve(img); // 停止觀察已開(kāi)始加載的圖片
        }
    })
}, {});
Array.from(document.querySelectorAll('img')).forEach((item) => {
  observer.observe(item)  //觀察所有圖片資源,開(kāi)始觀察item
});
2.1.3 實(shí)例:無(wú)限滾動(dòng)
無(wú)限滾動(dòng)時(shí),在頁(yè)面底部加一個(gè)footerSentinel元素。一旦footerSentinel可見(jiàn),就表示頁(yè)面滾動(dòng)到了底部,從而加載新的條目放在footerSentinel前面。

const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if (entry.intersectionRatio <= 0) return; // 如果不可見(jiàn),就返回
        let newData = [1,2,3,4,5];
        appendChildBeforeFooter(newData); //新數(shù)據(jù)追加在footerSentinel之前
    })
});

// 開(kāi)始觀察
observer.observe(
  document.querySelector('.footerSentinel')
);
2.1.4 實(shí)例:網(wǎng)頁(yè)廣告的曝光量統(tǒng)計(jì)
很多時(shí)候,廣告圖片不一定需要全部展示才算被用戶看到,有時(shí)候圖片只展示了60%時(shí),主要信息已經(jīng)被用戶看到,這種情況其實(shí)是可以算作一次曝光量的統(tǒng)計(jì)。為了實(shí)現(xiàn)這種廣告的曝光量的精確統(tǒng)計(jì),我們可以創(chuàng)建交叉管理器,觀察到廣告目標(biāo)元素的交叉比例intersectionRatio達(dá)到0.6時(shí),判定廣告的曝光量+1

 const intersectionObserver = new IntersectionObserver((entries)=> {
     entries.forEach(entry => {
         if(entry.intersectionRatio > 0){
            console.log('info:');
            console.log('廣告位元素和可視區(qū)域相交部分的比例:'+entry.intersectionRatio + ',廣告曝光量?1')
            intersectionObserver.unobserve(document.querySelector('.DemoIntersectionObserver .ad'))
         }
     })
 },{
     threshold: 0.6,
 });
intersectionObserver.observe(document.querySelector('.DemoIntersectionObserver .ad'));
看一下實(shí)際效果



2.2 MutationObserver 變化觀察器
該觀察器"觀察"目標(biāo)元素屬性和子節(jié)點(diǎn)的變化。目標(biāo)元素DOM發(fā)生變動(dòng)就會(huì)觸發(fā)觀察器的回調(diào)函數(shù)。注意:異步觸發(fā),DOM的變動(dòng)并不會(huì)馬上觸發(fā),而是要等到當(dāng)前所有DOM操作都結(jié)束才觸發(fā)。

2.2.1 基本用法
定義觀察到目標(biāo)元素的特定變動(dòng)時(shí)的回調(diào)函數(shù)callback(mutationList, observer)回調(diào)函數(shù),mutationList為包含目標(biāo)元素DOM變化相關(guān)信息的對(duì)象的數(shù)組,數(shù)組中,每個(gè)成員都是一個(gè)MutationRecord對(duì)象
let callback = (mutationList, observer)  => {
    mutationList.forEach((mutation) => {
    console.log(mutation.target) //發(fā)生變動(dòng)的DOM節(jié)點(diǎn)
    console.log(mutation.previousSibling) //前一個(gè)同級(jí)節(jié)點(diǎn),如果沒(méi)有則返回null。
    console.log(mutation.nextSibling) //下一個(gè)同級(jí)節(jié)點(diǎn),如果沒(méi)有則返回null。
    switch(mutation.type) {//目標(biāo)元素變化類(lèi)型'childList' || 'attributes' | 'characterData'
        case 'childList':
            console.log(mutation.addedNodes) //新增的 DOM 節(jié)點(diǎn)
            console.log(mutation.removedNodes) //刪除的 DOM 節(jié)點(diǎn)
            break;
        case 'attributes':
            console.log(mutation.attributeName) //被更改的屬性名稱,如果設(shè)置了attributeFilter,則只返回預(yù)先指定的屬性。
            console.log(mutation.oldValue) //該屬性之前的值,這個(gè)屬性只對(duì)attribute和characterData變動(dòng)有效,如果發(fā)生childList變動(dòng),則返回null。
            break;
        }
    });
};





通過(guò)new MutationObserver(callback) 創(chuàng)建觀察器實(shí)例 observer
let observer = new MutationObserver(callback);
observer.observe(targetNode[, options]), 按照options配置指定要觀察的特定變動(dòng),并開(kāi)始觀察目標(biāo)元素 targetNode。其中:childList,attributes、characterData 三個(gè)DOM變動(dòng)類(lèi)型的屬性之中,至少有一個(gè)必須為true,若均未指定將報(bào)錯(cuò)。
let targetNode = document.querySelector("#someElement");
let options = {
    childList: true,  //  DOM 變動(dòng)類(lèi)型:是否觀察目標(biāo)子節(jié)點(diǎn)添加或刪除,默認(rèn)為false。
    attributes: true, //  DOM 變動(dòng)類(lèi)型:是否觀察目標(biāo)節(jié)點(diǎn)屬性變動(dòng),默認(rèn)為false。
    characterData: false, //  DOM 變動(dòng)類(lèi)型:是否觀察文本節(jié)點(diǎn)變化。無(wú)默認(rèn)值
    subtree: true, // 是否觀察后代節(jié)點(diǎn),默認(rèn)為false。
    //注意:childList,attributes、characterData 三個(gè)屬性之中,至少有一個(gè)必須為 true
    // attributeOldValue: true, //表示觀察attributes變動(dòng)時(shí),是否需要記錄變動(dòng)前的屬性值。
    // characterDataOldValue: true, //表示觀察characterData變動(dòng)時(shí),是否需要記錄變動(dòng)前的值。
    // attributeFilter: ['class','src'], //數(shù)組,表示需要觀察的特定屬性(比如['class','src'])。
}
observer.observe(targetNode, options); //開(kāi)始觀察目標(biāo)元素,按照options配置指定所要觀察的特定變動(dòng)。
// observer.disconnect(); //停止觀察。
// observer.takeRecords(); //返回所有觀察目標(biāo)對(duì)象數(shù)組。
2.3 ResizeObserver 大小觀察器 (實(shí)驗(yàn))
該觀察器"觀察"Element內(nèi)容區(qū)域的改變或SVGElement的邊界框的改變,每次元素內(nèi)容或邊框的大小變化時(shí)都會(huì)向觀察者傳遞通知。

2.3.1 基本用法
定義觀察到目標(biāo)元素的大小變化的回調(diào)函數(shù)callback(entries, observer),entries為包含目標(biāo)元素大小變化的相關(guān)信息的數(shù)組,數(shù)組中,每個(gè)成員都是一個(gè)ResizeObserverEntry對(duì)象
let callback = (entries, observer) => {
    entries.forEach(entry => {
        console.log('當(dāng)前大小', `${entry.contentRect.width} x ${entry.contentRect.height}`)
        /**
         * entry.target :目標(biāo)元素
         * entry.borderBoxSize: 包含目標(biāo)元素的新邊框框大小的對(duì)象
         * entry.contentBoxSize: 包含目標(biāo)元素的新內(nèi)容框大小的對(duì)象
         * entry.contentRect: 包含目標(biāo)元素的新大小的對(duì)象
         * entry.devicePixelContentBoxSize 包含目標(biāo)元素以設(shè)備像素為單位的新內(nèi)容框大小的對(duì)象
         * */
    });
}
通過(guò)new ResizeObserver(callback) 創(chuàng)建觀察器實(shí)例 observer
let observer = new ResizeObserver(callback);
observer.observe(targetNode); 開(kāi)始觀察目標(biāo)元素 targetNode。
let targetNode = document.querySelector("#someElement");
observer.observe(targetNode);//開(kāi)始觀察目標(biāo)元素
// observer.disconnect(); //停止觀察。
// observer.takeRecords(targetNode); //停止觀察目標(biāo)元素。
2.4 PerformanceObserver 性能觀察器
該觀察器用于“觀察”記錄 performance 數(shù)據(jù)的行為,一旦記錄了就會(huì)觸發(fā)回調(diào),可以在回調(diào)里上報(bào)這些性能相關(guān)的數(shù)據(jù)。

瀏覽器API performance 用于記錄一些時(shí)間點(diǎn)、某個(gè)時(shí)間段、資源加載的耗時(shí)等;附上:performance詳細(xì)用法

2.4.1 基本用法
定義觀察到目標(biāo)元素的特定變動(dòng)時(shí)的回調(diào)函數(shù)callback(list, observer)。list.getEntries()為包含options中指定的相關(guān)performance數(shù)據(jù)的對(duì)象的數(shù)組,每個(gè)成員都是一個(gè)PerformanceEntry對(duì)象
let callback = (list, observer) => {
    list.getEntries().forEach(entry => {
        console.log(entry); //entry為按startTime排序的performance上報(bào)的數(shù)據(jù)對(duì)象,自動(dòng)根據(jù)所請(qǐng)求資源的變化而改變,也可以用mark(),measure()方法自定義添加
        /**
         * entry.name:資源名稱,是資源的絕對(duì)路徑或調(diào)用mark方法自定義的名稱
         * entry.entryType:資源類(lèi)型,entryType類(lèi)型不同數(shù)組中的對(duì)象結(jié)構(gòu)也不同
         * entry.startTime:開(kāi)始時(shí)間
         * entry.duration:加載時(shí)間
         * entry.entryType == 'paint' && entry.name == 'first-paint':'首次繪制,繪制Body',
         * entry.entryType == 'paint' && entry.name == 'first-contentful-paint':'首次有內(nèi)容的繪制,第一個(gè)dom元素繪制完成',
         * entry.entryType == 'paint' && entry.name == 'first-meaningful-paint':'首次有意義的繪制',
        */
    });
}
通過(guò)new PerformanceObserver(callback) 創(chuàng)建觀察器實(shí)例 observer
const observer = new PerformanceObserver(callback)
observer.observe(options), 按照options配置,指定所要觀察的performance數(shù)據(jù)相關(guān)變化。
let options = {
    entryTypes:[// 類(lèi)型為string[],必填,且數(shù)組不能為空,數(shù)組中某個(gè)字符串取的值無(wú)效,瀏覽器會(huì)自動(dòng)忽略它
        'longtask', // 長(zhǎng)任務(wù) (>50ms)
        'frame', // 幀的變化,常用于動(dòng)畫(huà)監(jiān)聽(tīng),使用時(shí)注意兼容
        'navigation', // 頁(yè)面加載||刷新||重定向
        'resource', // 資源加載
        'mark',//  自定義記錄的某個(gè)時(shí)間點(diǎn)
        'measure',//  自定義記錄的某個(gè)時(shí)間段
        'paint'//  瀏覽器繪制
    ]
};
observer.observe(options); //當(dāng)記錄的性能指標(biāo)在指定的 entryTypes 之中時(shí),將調(diào)用性能觀察器的回調(diào)函數(shù)。
// observer.disconnect(); //阻止性能觀察器接收任何性能指標(biāo)事件。
// observer.takeRecords(); //返回存儲(chǔ)在性能觀察器中的性能指標(biāo)的列表,并將其清空。
2.4.2 實(shí)例:“小雞仔的一生”
下面我們通過(guò)”小雞仔的一生“來(lái)看一下MutationObserver、ResizeObserver、PerformanceObserver的使用。

首先,它是只會(huì)下蛋的母雞,但雞蛋時(shí)而被偷。且現(xiàn)在疫情肆虐,小雞可能會(huì)發(fā)燒生病,需隨時(shí)關(guān)注小雞的健康狀態(tài),及時(shí)收雞蛋。等到小雞長(zhǎng)大“成熟”,給它賣(mài)掉。并記錄下顧客看到小雞的商品圖到真正下單的間隔時(shí)長(zhǎng)。

首先給小雞搭建好“籠子”,把“小雞”和“雞蛋”放進(jìn)去

    <div class="Demo">
      <div class="chicken normal">
        <img src='./image/chicken.jpeg' alt="" />
        <div class="egg"></div>
      </div>
    </div>
創(chuàng)建MutationObserver觀察器,觀察小雞的變化,觀察到它的“健康屬性”className變化和“雞蛋”(子節(jié)點(diǎn))數(shù)量變化時(shí),分別“提醒”小雞健康狀態(tài)和雞蛋個(gè)數(shù)變化如下

   const mutationObserver = new MutationObserver((mutationsList) => {
   mutationsList.forEach((mutation) => {
       switch(mutation.type) {
         case 'childList':
             if(mutation.addedNodes.length>0){console.log('小雞下蛋了') }
             else if(mutation.removedNodes.length>0){ console.log('雞蛋被偷了1個(gè)') }
             break;
         case 'attributes':
           if(mutation.target.className.indexOf('hot')>-1){ console.log('小雞發(fā)燒了') }
           else{ console.log('小雞健康') }
           break;
       }
   });
   });
   mutationObserver.observe(document.querySelector('.Demo .chicken'),{childList: true,attributes: true,});
創(chuàng)建ResizeObserver觀察器,觀察小雞的大小的變化,當(dāng)小雞“成熟”時(shí),將小雞“賣(mài)出”

    const resizeObserver = new ResizeObserver(entries => {
    entries.forEach(entry => {
        if(entry.contentRect.width > 200){
            console.log('小雞賣(mài)出!當(dāng)前大小', `${entry.contentRect.width} x ${entry.contentRect.height}`)
        }
        else
            console.log('小雞當(dāng)前大小', `${entry.contentRect.width} x ${entry.contentRect.height}`)
    });
    });
    resizeObserver.observe(document.querySelector(".Demo .chicken img"));
</html>
創(chuàng)建定時(shí)器,隨機(jī)更新小雞的健康狀態(tài)和雞蛋個(gè)數(shù), 并隨機(jī)更新小雞的大小

   let timer = setInterval(() => {
   let random = Math.ceil(Math.random() * 4);
   targetNodeImg?.setAttribute('style',`width:${targetNodeImg.offsetWidth*1.2}px`)
   switch (random) {
       case 1: targetNodes.className="chicken hot";break;
       case 2: targetNodes.className="chicken";break;
       case 3: const dom = document.createElement('div'); dom.className = 'egg'; targetNodes.appendChild(dom);targetNodes.appendChild(dom.cloneNode());break;
       case 4: document.querySelectorAll('.egg')[0]&&document.querySelectorAll('.egg')[0].remove(); break;
       default:break;
   }
   },2000);
小雞已經(jīng)“成熟”,停止觀察,并清空定時(shí)器,然后展示小雞的商品頁(yè)

    setTimeout(()=>{
        clearInterval(timer)
        mutationObserver.disconnect();
        resizeObserver.disconnect();
        //此時(shí),小雞已經(jīng)“成熟”,展示商品頁(yè)信息
    },16000)
</html>
小雞的商品頁(yè),初始化查看商品等方法。查看商品時(shí),記錄一個(gè)時(shí)間點(diǎn)Start-Mark,下單時(shí),記錄一個(gè)時(shí)間點(diǎn)End-Mark,上報(bào)時(shí)間Start-End-Send為End-Mark-Start-Mark。

function startMark() { performance.mark('Start-Mark') } //查看商品
function endMark() { performance.mark('End-Mark') } //下單
function measureClick() { performance.measure('Start-End-Send','Start-Mark','End-Mark'); } //上報(bào)點(diǎn)擊【查看商品】到點(diǎn)【下單】中間所用的時(shí)間
創(chuàng)建PerformanceObserver觀察器,觀察到performance上報(bào)的數(shù)據(jù)時(shí),打印對(duì)應(yīng)的時(shí)間等數(shù)據(jù)信息(這其中就包含了我們記錄的mark信息和頁(yè)面資源加載等信息)。

let callback = (list, observer) => {
    list.getEntries().forEach(entry => {
      switch (entry.entryType) {
        case 'mark':console.log(`(自定義上報(bào)-時(shí)間點(diǎn)):${entry.name},時(shí)刻:  - ${entry.startTime}`);break;
        case 'measure':console.log(`(自定義上報(bào)-時(shí)間段):${entry.name},時(shí)間: ${entry.duration} `);break;
        default:break;
      }  
    });
}
const observer = new PerformanceObserver(callback)
observer.observe({ entryTypes:['mark','measure'] });
小雞仔“長(zhǎng)大”到被“賣(mài)出”,效果展示

2.5 ReportingObserver 報(bào)告觀察器(實(shí)驗(yàn))
該觀察器“觀察”過(guò)時(shí)的api、瀏覽器的一些干預(yù)行為報(bào)告,在回調(diào)里上報(bào)

2.5.1 基本用法
通過(guò)new ReportingObserver(callback,options)創(chuàng)建觀察器實(shí)例, 按照options配置指定所要觀察的report數(shù)據(jù)。觀察到有報(bào)告數(shù)據(jù)時(shí),調(diào)取callback(reports, observer)回調(diào)函數(shù),reports為包含options中指定的相關(guān)報(bào)告數(shù)據(jù)的對(duì)象report的數(shù)組;
let options = {
    types: ['intervention', 'deprecation'] //string[], ??捎弥涤校篸eprecation(觀察使用過(guò)時(shí)的api)、 intervention(觀察[瀏覽器干預(yù)行為](https://chromestatus.com/features#intervention))
    //buffered: 在觀察者能夠被創(chuàng)建之前生成的報(bào)告是否應(yīng)該是可觀察的;可觀察的(true) 或不可觀察的 (false)
};
let callback = (reports, observer) => {
    reports.forEach(report => {
        console.log(report.body);// 返回report正文,包含詳細(xì)的report對(duì)象,目前只有兩種body對(duì)象(取決于type的返回值)
        // report.type 生成的報(bào)告類(lèi)型,例如deprecation或intervention。
        // report.url 生成報(bào)告的文檔的 URL。
    });
}
const observer = new ReportingObserver(callback, options) //創(chuàng)建觀察器實(shí)例, 按照`options`配置指定所要觀察的report數(shù)據(jù)。
observer.observe()開(kāi)始觀察options中指定的報(bào)告隊(duì)列中收集報(bào)告,數(shù)據(jù)上報(bào)時(shí)調(diào)用回調(diào)函數(shù)
observer.observe(); //開(kāi)始觀察options中指定的報(bào)告隊(duì)列中收集報(bào)告,數(shù)據(jù)上報(bào)時(shí)調(diào)用回調(diào)函數(shù) 。
// observer.disconnect(); //阻止之前開(kāi)始觀察的報(bào)告觀察者收集報(bào)告。
// observer.takeRecords(); //返回當(dāng)前包含在觀察者報(bào)告隊(duì)列中的報(bào)告列表,并清空隊(duì)列。
注意:報(bào)告觀察器現(xiàn)在還是試驗(yàn)性的API,瀏覽器的支持程度還不夠,尤其是Safari瀏覽器完全不支持。其他觀察器相對(duì)比較成熟,但也存在部分兼容問(wèn)題,使用時(shí)要視具體情況考慮



三、總結(jié)
通過(guò)以上介紹,相信大家對(duì)瀏覽器的5種觀察器都有了一定了解。
如果你還知道這些觀察器的其他用法,歡迎評(píng)論區(qū)留言。
如果文中有哪些地方寫(xiě)得不好、不對(duì)的地方,歡迎大家批評(píng)指正,感謝您的閱讀,今天也是元?dú)鉂M滿的一天,一起加油呦!



作者:大轉(zhuǎn)轉(zhuǎn)FE


歡迎關(guān)注微信公眾號(hào) :前端印象