1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        這幾個(gè)高級(jí)前端常用的 API,你用到了嗎?

        共 5302字,需瀏覽 11分鐘

         ·

        2022-05-15 22:25

        推薦關(guān)注↓

        本文在github做了收錄 github.com/Michael-lzg/my--article/blob/master/other/分享幾個(gè)實(shí)用的API.md

        • MutationObserver

        • IntersectionObserver

        • getComputedStyle()

        • getBoundingClientRect

        • requestAnimationFrame

        MutationObserver

        MutationObserver 是一個(gè)可以監(jiān)聽(tīng) DOM 結(jié)構(gòu)變化的接口。當(dāng) DOM 對(duì)象樹(shù)發(fā)生任何變動(dòng)時(shí),MutationObserver 會(huì)得到通知。

        API

        MutationObserver 是一個(gè)構(gòu)造器,接受一個(gè) callback 參數(shù),用來(lái)處理節(jié)點(diǎn)變化的回調(diào)函數(shù),返回兩個(gè)參數(shù):

        • mutations:節(jié)點(diǎn)變化記錄列表(sequence
        • observer:構(gòu)造 MutationObserver 對(duì)象。

        MutationObserver 對(duì)象有三個(gè)方法,分別如下:

        • observe:設(shè)置觀察目標(biāo),接受兩個(gè)參數(shù),target:觀察目標(biāo),options:通過(guò)對(duì)象成員來(lái)設(shè)置觀察選項(xiàng)
        • disconnect:阻止觀察者觀察任何改變
        • takeRecords:清空記錄隊(duì)列并返回里面的內(nèi)容
        //選擇一個(gè)需要觀察的節(jié)點(diǎn)
        var?targetNode?=?document.getElementById('root')

        //?設(shè)置observer的配置選項(xiàng)
        var?config?=?{?attributes:?true,?childList:?true,?subtree:?true?}

        //?當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)的需要執(zhí)行的函數(shù)
        var?callback?=?function?(mutationsList,?observer)?{
        ??for?(var?mutation?of?mutationsList)?{
        ????if?(mutation.type?==?'childList')?{
        ??????console.log('A?child?node?has?been?added?or?removed.')
        ????}?else?if?(mutation.type?==?'attributes')?{
        ??????console.log('The?'?+?mutation.attributeName?+?'?attribute?was?modified.')
        ????}
        ??}
        }

        //?創(chuàng)建一個(gè)observer示例與回調(diào)函數(shù)相關(guān)聯(lián)
        var?observer?=?new?MutationObserver(callback)

        //使用配置文件對(duì)目標(biāo)節(jié)點(diǎn)進(jìn)行觀測(cè)
        observer.observe(targetNode,?config)

        //?停止觀測(cè)
        observer.disconnect()

        observe 方法中 options 參數(shù)有已下幾個(gè)選項(xiàng):

        • childList:設(shè)置 true,表示觀察目標(biāo)子節(jié)點(diǎn)的變化,比如添加或者刪除目標(biāo)子節(jié)點(diǎn),不包括修改子節(jié)點(diǎn)以及子節(jié)點(diǎn)后代的變化
        • attributes:設(shè)置 true,表示觀察目標(biāo)屬性的改變
        • characterData:設(shè)置 true,表示觀察目標(biāo)數(shù)據(jù)的改變
        • subtree:設(shè)置為 true,目標(biāo)以及目標(biāo)的后代改變都會(huì)觀察
        • attributeOldValue:如果屬性為 true 或者省略,則相當(dāng)于設(shè)置為 true,表示需要記錄改變前的目標(biāo)屬性值,設(shè)置了 attributeOldValue 可以省略 attributes 設(shè)置
        • characterDataOldValue:如果 characterData 為 true 或省略,則相當(dāng)于設(shè)置為 true,表示需要記錄改變之前的目標(biāo)數(shù)據(jù),設(shè)置了 characterDataOldValue 可以省略 characterData 設(shè)置
        • attributeFilter:如果不是所有的屬性改變都需要被觀察,并且 attributes 設(shè)置為 true 或者被忽略,那么設(shè)置一個(gè)需要觀察的屬性本地名稱(chēng)(不需要命名空間)的列表

        特點(diǎn)

        MutationObserver 有以下特點(diǎn):

        • 它等待所有腳本任務(wù)完成后才會(huì)運(yùn)行,即采用異步方式
        • 它把 DOM 變動(dòng)記錄封裝成一個(gè)數(shù)組進(jìn)行處理,而不是一條條地個(gè)別處理 DOM 變動(dòng)。
        • 它即可以觀察發(fā)生在 DOM 節(jié)點(diǎn)的所有變動(dòng),也可以觀察某一類(lèi)變動(dòng)

        當(dāng) DOM 發(fā)生變動(dòng)會(huì)觸發(fā) MutationObserver 事件。但是,它與事件有一個(gè)本質(zhì)不同:事件是同步觸發(fā),也就是說(shuō) DOM 發(fā)生變動(dòng)立刻會(huì)觸發(fā)相應(yīng)的事件;MutationObserver 則是異步觸發(fā),DOM 發(fā)生變動(dòng)以后,并不會(huì)馬上觸發(fā),而是要等到當(dāng)前所有 DOM 操作都結(jié)束后才觸發(fā)。

        舉例來(lái)說(shuō),如果在文檔中連續(xù)插入 1000 個(gè)段落(p 元素),會(huì)連續(xù)觸發(fā) 1000 個(gè)插入事件,執(zhí)行每個(gè)事件的回調(diào)函數(shù),這很可能造成瀏覽器的卡頓;而 MutationObserver 完全不同,只在 1000 個(gè)段落都插入結(jié)束后才會(huì)觸發(fā),而且只觸發(fā)一次,這樣較少了 DOM 的頻繁變動(dòng),大大有利于性能。

        IntersectionObserver

        網(wǎng)頁(yè)開(kāi)發(fā)時(shí),常常需要了解某個(gè)元素是否進(jìn)入了"視口"(viewport),即用戶能不能看到它。

        傳統(tǒng)的實(shí)現(xiàn)方法是,監(jiān)聽(tīng)到 scroll 事件后,調(diào)用目標(biāo)元素的 getBoundingClientRect()方法,得到它對(duì)應(yīng)于視口左上角的坐標(biāo),再判斷是否在視口之內(nèi)。這種方法的缺點(diǎn)是,由于 scroll 事件密集發(fā)生,計(jì)算量很大,容易造成性能問(wèn)題。

        目前有一個(gè)新的 IntersectionObserver API,可以自動(dòng)"觀察"元素是否可見(jiàn),Chrome 51+ 已經(jīng)支持。由于可見(jiàn)(visible)的本質(zhì)是,目標(biāo)元素與視口產(chǎn)生一個(gè)交叉區(qū),所以這個(gè) API 叫做"交叉觀察器"。

        API

        IntersectionObserver 是瀏覽器原生提供的構(gòu)造函數(shù),接受兩個(gè)參數(shù):callback 是可見(jiàn)性變化時(shí)的回調(diào)函數(shù),option 是配置對(duì)象(該參數(shù)可選)。

        var?io?=?new?IntersectionObserver(callback,?option)

        //?開(kāi)始觀察
        io.observe(document.getElementById('example'))

        //?停止觀察
        io.unobserve(element)

        //?關(guān)閉觀察器
        io.disconnect()

        如果要觀察多個(gè)節(jié)點(diǎn),就要多次調(diào)用這個(gè)方法。

        io.observe(elementA)
        io.observe(elementB)

        目標(biāo)元素的可見(jiàn)性變化時(shí),就會(huì)調(diào)用觀察器的回調(diào)函數(shù) callback。callback 一般會(huì)觸發(fā)兩次。一次是目標(biāo)元素剛剛進(jìn)入視口(開(kāi)始可見(jiàn)),另一次是完全離開(kāi)視口(開(kāi)始不可見(jiàn))。

        var?io?=?new?IntersectionObserver((entries)?=>?{
        ??console.log(entries)
        })

        callback 函數(shù)的參數(shù)(entries)是一個(gè)數(shù)組,每個(gè)成員都是一個(gè) IntersectionObserverEntry 對(duì)象。舉例來(lái)說(shuō),如果同時(shí)有兩個(gè)被觀察的對(duì)象的可見(jiàn)性發(fā)生變化,entries 數(shù)組就會(huì)有兩個(gè)成員。

        • time:可見(jiàn)性發(fā)生變化的時(shí)間,是一個(gè)高精度時(shí)間戳,單位為毫秒
        • target:被觀察的目標(biāo)元素,是一個(gè) DOM 節(jié)點(diǎn)對(duì)象
        • isIntersecting: 目標(biāo)是否可見(jiàn)
        • rootBounds:根元素的矩形區(qū)域的信息,getBoundingClientRect()方法的返回值,如果沒(méi)有根元素(即直接相對(duì)于視口滾動(dòng)),則返回 null
        • boundingClientRect:目標(biāo)元素的矩形區(qū)域的信息
        • intersectionRect:目標(biāo)元素與視口(或根元素)的交叉區(qū)域的信息
        • intersectionRatio:目標(biāo)元素的可見(jiàn)比例,即 intersectionRect 占 boundingClientRect 的比例,完全可見(jiàn)時(shí)為 1,完全不可見(jiàn)時(shí)小于等于 0

        舉個(gè)例子

        <html?lang="en">
        ??<head>
        ????<meta?charset="UTF-8"?/>
        ????<title>Documenttitle>
        ????<style>
        ??????#div1?{
        ????????position:?sticky;
        ????????top:?0;
        ????????height:?50px;
        ????????line-height:?50px;
        ????????text-align:?center;
        ????????background:?black;
        ????????color:?#ffffff;
        ????????font-size:?18px;
        ??????}
        ????
        style>
        ??head>

        ??<body>
        ????<div?id="div1">首頁(yè)div>
        ????<div?style="height:?1000px;">div>
        ????<div?id="div2"?style="height:?100px;?background:?red;">div>
        ????<script>
        ??????var?div2?=?document.getElementById('div2')
        ??????let?observer?=?new?IntersectionObserver(
        ????????function?(entries)?{
        ??????????entries.forEach(function?(element,?index)?{
        ????????????console.log(element)
        ????????????if?(element.isIntersecting)?{
        ??????????????div1.innerText?=?'我出來(lái)了'
        ????????????}?else?{
        ??????????????div1.innerText?=?'首頁(yè)'
        ????????????}
        ??????????})
        ????????},
        ????????{
        ??????????root:?null,
        ??????????threshold:?[0,?1]
        ????????}
        ??????)

        ??????observer.observe(div2)
        ????
        script>
        ??body>
        html>

        相比于 getBoundingClientRect,它的優(yōu)點(diǎn)是不會(huì)引起重繪回流。兼容性如下

        ce1aacb7ef401638fdedfd742041bfde.webp

        圖片懶加載

        圖片懶加載的原理主要是判斷當(dāng)前圖片是否到了可視區(qū)域這一核心邏輯實(shí)現(xiàn)的。這樣可以節(jié)省帶寬,提高網(wǎng)頁(yè)性能。

        傳統(tǒng)的突破懶加載是通過(guò)監(jiān)聽(tīng) scroll 事件實(shí)現(xiàn)的,但是 scroll 事件會(huì)在很短的時(shí)間內(nèi)觸發(fā)很多次,嚴(yán)重影響頁(yè)面性能。為提高頁(yè)面性能,我們可以使用 IntersectionObserver 來(lái)實(shí)現(xiàn)圖片懶加載。

        const?imgs?=?document.querySelectorAll('img[src]')
        const?config?=?{
        ??rootMargin:?'0px',
        ??threshold:?0
        }
        let?observer?=?new?IntersectionObserver((entries,?self)?=>?{
        ??entries.forEach((entry)?=>?{
        ????if?(entry.isIntersecting)?{
        ??????let?img?=?entry.target
        ??????let?src?=?img.dataset.src
        ??????if?(src)?{
        ????????img.src?=?src
        ????????img.removeAttribute('src')
        ??????}
        ??????//?解除觀察
        ??????self.unobserve(entry.target)
        ????}
        ??})
        },?config)

        imgs.forEach((image)?=>?{
        ??observer.observe(image)
        })

        無(wú)限滾動(dòng)

        無(wú)限滾動(dòng)(infinite scroll)的實(shí)現(xiàn)也很簡(jiǎn)單。

        var?intersectionObserver?=?new?IntersectionObserver(function?(entries)?{
        ??//?如果不可見(jiàn),就返回
        ??if?(entries[0].intersectionRatio?<=?0)?return
        ??loadItems(10)
        ??console.log('Loaded?new?items')
        })

        //?開(kāi)始觀察
        intersectionObserver.observe(document.querySelector('.scrollerFooter'))

        getComputedStyle()

        DOM2 Style 在?document.defaultView?上增加了 getComputedStyle()方法,該方法返回一個(gè)?CSSStyleDeclaration?對(duì)象(與 style 屬性的類(lèi)型一樣),包含元素的計(jì)算樣式。

        API

        document.defaultView.getComputedStyle(element[,pseudo-element])
        //?or
        window.getComputedStyle(element[,pseudo-element])

        這個(gè)方法接收兩個(gè)參數(shù):要取得計(jì)算樣式的元素和偽元素字符串(如":after")。如果不需要查詢(xún)偽元素,則第二個(gè)參數(shù)可以傳 null。

        html>
        <html>?
        ??<head>??
        ????<style?type="text/css">????
        ??????#myDiv?{?????
        ????????background-color:?blue;????
        ????????width:?100px;????
        ????????height:?200px;???
        ??????}??
        ????
        style>
        ??head>?
        ??<body>??
        ????<div?id="myDiv"?style="background-color:?red;?border:?1px?solid?black">div>?
        ??body>?
        ??<script>??
        ????function?getStyleByAttr(obj,?name)?{???
        ??????return?window.getComputedStyle???window.getComputedStyle(obj,?null)[name]?:?obj.currentStyle[name]??
        ????}???
        ????let?node?=?document.getElementById('myDiv')??
        ????console.log(getStyleByAttr(node,?'backgroundColor'))??
        ????console.log(getStyleByAttr(node,?'width'))??
        ????console.log(getStyleByAttr(node,?'height'))??
        ????console.log(getStyleByAttr(node,?'border'))?
        ??
        script>
        html>

        和 style 的異同

        getComputedStyle 和 element.style 的相同點(diǎn)就是二者返回的都是 CSSStyleDeclaration 對(duì)象。而不同點(diǎn)就是:

        • element.style 讀取的只是元素的內(nèi)聯(lián)樣式,即寫(xiě)在元素的 style 屬性上的樣式;而 getComputedStyle 讀取的樣式是最終樣式,包括了內(nèi)聯(lián)樣式、嵌入樣式和外部樣式。
        • element.style 既支持讀也支持寫(xiě),我們通過(guò) element.style 即可改寫(xiě)元素的樣式。而 getComputedStyle 僅支持讀并不支持寫(xiě)入。我們可以通過(guò)使用 getComputedStyle 讀取樣式,通過(guò) element.style 修改樣式

        getBoundingClientRect

        getBoundingClientRect() 方法返回元素的大小及其相對(duì)于視口的位置。

        API

        let?DOMRect?=?object.getBoundingClientRect()

        它的返回值是一個(gè) DOMRect 對(duì)象,這個(gè)對(duì)象是由該元素的 getClientRects() 方法返回的一組矩形的集合,就是該元素的 CSS 邊框大小。

        返回的結(jié)果是包含完整元素的最小矩形,并且擁有 left, top, right, bottom, x, y, width, 和 height 這幾個(gè)以像素為單位的只讀屬性用于描述整個(gè)邊框。除了 width 和 height 以外的屬性是相對(duì)于視圖窗口的左上角來(lái)計(jì)算的。

        b9fa6ec21a7041d254a0daabfb3618ec.webp

        應(yīng)用場(chǎng)景

        1、獲取 dom 元素相對(duì)于網(wǎng)頁(yè)左上角定位的距離

        以前的寫(xiě)法是通過(guò) offsetParent 找到元素到定位父級(jí)元素,直至遞歸到頂級(jí)元素 body 或 html。

        //?獲取dom元素相對(duì)于網(wǎng)頁(yè)左上角定位的距離
        function?offset(el)?{?
        ??var?top?=?0?
        ??var?left?=?0?
        ??do?{??
        ????top?+=?el.offsetTop??
        ????left?+=?el.offsetLeft?
        ??}?while?((el?=?el.offsetParent))?//?存在兼容性問(wèn)題,需要兼容?
        ??return?{?
        ????top:?top,??
        ????left:?left?
        ??}
        }

        var?odiv?=?document.getElementsByClassName('markdown-body')
        offset(a[0])?//?{top:?271,?left:?136}

        現(xiàn)在根據(jù) getBoundingClientRect 這個(gè) api,可以寫(xiě)成這樣:

        var?positionX?=?this.getBoundingClientRect().left?+?document.documentElement.scrollLeft
        var?positionY?=?this.getBoundingClientRect().top?+?document.documentElement.scrollTop

        2、判斷元素是否在可視區(qū)域內(nèi)

        function?isElView(el)?{?
        ??var?top?=?el.getBoundingClientRect().top?//?元素頂端到可見(jiàn)區(qū)域頂端的距離?
        ??var?bottom?=?el.getBoundingClientRect().bottom?//?元素底部端到可見(jiàn)區(qū)域頂端的距離?
        ??var?se?=?document.documentElement.clientHeight?//?瀏覽器可見(jiàn)區(qū)域高度。?
        ??if?(top??0)?{???
        ????return?true?
        ??}?else?if?(top?>=?se?||?bottom?<=?0)?{??
        ????//?不可見(jiàn)?
        ??}?
        ??return?false
        }

        requestAnimationFrame

        window.requestAnimationFrame() 告訴瀏覽器——你希望執(zhí)行一個(gè)動(dòng)畫(huà),并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動(dòng)畫(huà)。

        API

        該方法需要傳入一個(gè)回調(diào)函數(shù)作為參數(shù),該回調(diào)函數(shù)會(huì)在瀏覽器下一次重繪之前執(zhí)行。

        window.requestAnimationFrame(callback)

        兼容性處理

        window._requestAnimationFrame?=?(function?()?{?
        ??return?(?
        ????window.requestAnimationFrame?||???
        ????window.webkitRequestAnimationFrame?||??
        ????window.mozRequestAnimationFrame?||??
        ????function?(callback)?{????
        ??????window.setTimeout(callback,?1000?/?60)??
        ????}?
        ??)
        })()

        結(jié)束動(dòng)畫(huà)

        var?globalID
        function?animate()?{?
        ??//?done();?一直運(yùn)行?
        ??globalID?=?requestAnimationFrame(animate)?//?Do?something?animate
        }
        globalID?=?requestAnimationFrame(animate)?//開(kāi)始
        cancelAnimationFrame(globalID)?//結(jié)束

        與 setTimeout 相比,requestAnimationFrame 最大的優(yōu)勢(shì)是由系統(tǒng)來(lái)決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)。具體一點(diǎn)講,如果屏幕刷新率是 60Hz,那么回調(diào)函數(shù)就每 16.7ms 被執(zhí)行一次,如果刷新率是 75Hz,那么這個(gè)時(shí)間間隔就變成了 1000/75=13.3ms,換句話說(shuō)就是,requestAnimationFrame 的步伐跟著系統(tǒng)的刷新步伐走。

        它能保證回調(diào)函數(shù)在屏幕每一次的刷新間隔中只被執(zhí)行一次,這樣就不會(huì)引起丟幀現(xiàn)象,也不會(huì)導(dǎo)致動(dòng)畫(huà)出現(xiàn)卡頓的問(wèn)題。這個(gè) API 的調(diào)用很簡(jiǎn)單,如下所示:

        var?progress?=?0
        //回調(diào)函數(shù)
        function?render()?{
        ??progress?+=?1?//修改圖像的位置?
        ??if?(progress?100)?{??
        ????//在動(dòng)畫(huà)沒(méi)有結(jié)束前,遞歸渲染
        ????window.requestAnimationFrame(render)?
        ??}
        }
        //第一幀渲染
        window.requestAnimationFrame(render)

        優(yōu)點(diǎn):

        • CPU 節(jié)能:使用 setTimeout 實(shí)現(xiàn)的動(dòng)畫(huà),當(dāng)頁(yè)面被隱藏或最小化時(shí),setTimeout 仍然在后臺(tái)執(zhí)行動(dòng)畫(huà)任務(wù),由于此時(shí)頁(yè)面處于不可見(jiàn)或不可用狀態(tài),刷新動(dòng)畫(huà)是沒(méi)有意義的,完全是浪費(fèi) CPU 資源。
          而 requestAnimationFrame 則完全不同,當(dāng)頁(yè)面處理未激活的狀態(tài)下,該頁(yè)面的屏幕刷新任務(wù)也會(huì)被系統(tǒng)暫停,因此跟著系統(tǒng)步伐走的 requestAnimationFrame 也會(huì)停止渲染,當(dāng)頁(yè)面被激活時(shí),動(dòng)畫(huà)就從上次停留的地方繼續(xù)執(zhí)行,有效節(jié)省了 CPU 開(kāi)銷(xiāo)。

        • 函數(shù)節(jié)流:在高頻率事件(resize,scroll 等)中,為了防止在一個(gè)刷新間隔內(nèi)發(fā)生多次函數(shù)執(zhí)行,使用 requestAnimationFrame 可保證每個(gè)刷新間隔內(nèi),函數(shù)只被執(zhí)行一次,這樣既能保證流暢性,也能更好的節(jié)省函數(shù)執(zhí)行的開(kāi)銷(xiāo)。一個(gè)刷新間隔內(nèi)函數(shù)執(zhí)行多次時(shí)沒(méi)有意義的,因?yàn)轱@示器每 16.7ms 刷新一次,多次繪制并不會(huì)在屏幕上體現(xiàn)出來(lái)。

        應(yīng)用場(chǎng)景

        1、監(jiān)聽(tīng) scroll 函數(shù)

        頁(yè)面滾動(dòng)事件(scroll)的監(jiān)聽(tīng)函數(shù),就很適合用這個(gè) api,推遲到下一次重新渲染。

        $(window).on('scroll',?function?()?{
        ??window.requestAnimationFrame(scrollHandler)
        })

        平滑滾動(dòng)到頁(yè)面頂部

        const?scrollToTop?=?()?=>?{?
        ??const?c?=?document.documentElement.scrollTop?||?document.body.scrollTop?
        ??if?(c?>?0)?{??
        ????window.requestAnimationFrame(scrollToTop)?
        ????window.scrollTo(0,?c?-?c?/?8)?
        ??}
        }

        scrollToTop()

        2、大量數(shù)據(jù)渲染

        比如對(duì)十萬(wàn)條數(shù)據(jù)進(jìn)行渲染,主要由以下幾種方法:

        (1)使用定時(shí)器

        //需要插入的容器
        let?ul?=?document.getElementById('container')
        //?插入十萬(wàn)條數(shù)據(jù)
        let?total?=?100000
        //?一次插入?20?條
        let?once?=?20
        //總頁(yè)數(shù)
        let?page?=?total?/?once
        //每條記錄的索引
        let?index?=?0
        //循環(huán)加載數(shù)據(jù)
        function?loop(curTotal,?curIndex)?{?
        ??if?(curTotal?<=?0)?{??
        ????return?false?
        ??}??
        ??//每頁(yè)多少條
        ??let?pageCount?=?Math.min(curTotal,?once)?
        ??setTimeout(()?=>?{??
        ????for?(let?i?=?0;?i???????let?li?=?document.createElement('li')????
        ??????li.innerText?=?curIndex?+?i?+?'?:?'?+?~~(Math.random()?*?total)????
        ??????ul.appendChild(li)??
        ????}??
        ????loop(curTotal?-?pageCount,?curIndex?+?pageCount)?
        ??},?0)
        }
        loop(total,?index)

        (2)使用 requestAnimationFrame

        //需要插入的容器
        let?ul?=?document.getElementById('container')
        //?插入十萬(wàn)條數(shù)據(jù)
        let?total?=?100000
        //?一次插入?20?條
        let?once?=?20
        //總頁(yè)數(shù)
        let?page?=?total?/?once
        //每條記錄的索引
        let?index?=?0
        //循環(huán)加載數(shù)據(jù)
        function?loop(curTotal,?curIndex)?{
        ??if?(curTotal?<=?0)?{
        ????return?false
        ??}
        ??//每頁(yè)多少條
        ??let?pageCount?=?Math.min(curTotal,?once)
        ??window.requestAnimationFrame(function?()?{
        ????for?(let?i?=?0;?i???????let?li?=?document.createElement('li')
        ??????li.innerText?=?curIndex?+?i?+?'?:?'?+?~~(Math.random()?*?total)
        ??????ul.appendChild(li)
        ????}
        ????loop(curTotal?-?pageCount,?curIndex?+?pageCount)
        ??})
        }
        loop(total,?index)

        監(jiān)控卡頓方法

        每秒中計(jì)算一次網(wǎng)頁(yè)的 FPS,獲得一列數(shù)據(jù),然后分析。通俗地解釋就是,通過(guò) requestAnimationFrame API 來(lái)定時(shí)執(zhí)行一些 JS 代碼,如果瀏覽器卡頓,無(wú)法很好地保證渲染的頻率,1s 中 frame 無(wú)法達(dá)到 60 幀,即可間接地反映瀏覽器的渲染幀率。

        var?lastTime?=?performance.now()
        var?frame?=?0
        var?lastFameTime?=?performance.now()
        var?loop?=?function?(time)?{
        ??var?now?=?performance.now()
        ??var?fs?=?now?-?lastFameTime
        ??lastFameTime?=?now
        ??var?fps?=?Math.round(1000?/?fs)
        ??frame++
        ??if?(now?>?1000?+?lastTime)?{
        ????var?fps?=?Math.round((frame?*?1000)?/?(now?-?lastTime))
        ????frame?=?0
        ????lastTime?=?now
        ??}
        ??window.requestAnimationFrame(loop)
        }

        我們可以定義一些邊界值,比如連續(xù)出現(xiàn) 3 個(gè)低于 20 的 FPS 即可認(rèn)為網(wǎng)頁(yè)存在卡頓。

        作者:lzg9527?

        https://juejin.cn/post/7028744289890861063

        - EOF -


        60fece30fb34dbeb7e1c78efbd68bc71.webp

        加主頁(yè)君微信,不僅前端技能+1

        b54176be071e4703c8dbac4ee0b6be5f.webp00e222a1a85033ab3ff568ea1bc8ca5b.webp

        主頁(yè)君日常還會(huì)在個(gè)人微信分享前端開(kāi)發(fā)學(xué)習(xí)資源技術(shù)文章精選,不定期分享一些有意思的活動(dòng)、崗位內(nèi)推以及如何用技術(shù)做業(yè)余項(xiàng)目

        加個(gè)微信,打開(kāi)一扇窗



        推薦閱讀??點(diǎn)擊標(biāo)題可跳轉(zhuǎn)

        1、太卷了!瀏覽器也支持原生的深拷貝 API 了?

        2、vue 中 Axios 的封裝和 API 接口的管理

        3、Vue3.0 最新動(dòng)態(tài):script-setup 定稿,部分實(shí)驗(yàn)性 API 將棄用


        覺(jué)得本文對(duì)你有幫助?請(qǐng)分享給更多人

        推薦關(guān)注「前端大全」,提升前端技能

        點(diǎn)贊和在看就是最大的支持??

        瀏覽 44
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久久综合伊人 | 五月天激情国产综合 | www.人人cao | 欧美黑人巨大久久久精品一区 | 床戏高潮呻吟声片段 | 91精品久久久久久久久中文字幕 | 日本乱仑中文 | 操操操操操操逼 | 国产老师做www爽爽爽视频 | 久久超碰大香蕉 |