使用 passive 改善的滾屏性能
共 2021字,需瀏覽 5分鐘
·
2024-06-09 10:18
EventTarget.addEventListener() 方法將指定的監(jiān)聽(tīng)器注冊(cè)到 EventTarget 上,當(dāng)該對(duì)象觸發(fā)指定的事件時(shí),指定的回調(diào)函數(shù)就會(huì)被執(zhí)行。
語(yǔ)法
addEventListener(type, listener);addEventListener(type, listener, options);addEventListener(type, listener, useCapture);
參數(shù)
type
表示監(jiān)聽(tīng)事件類型的大小寫敏感的字符串。
listener
當(dāng)所監(jiān)聽(tīng)的事件類型觸發(fā)時(shí),會(huì)接收到一個(gè)事件通知(實(shí)現(xiàn)了 Event 接口的對(duì)象)對(duì)象。listener 必須是一個(gè)實(shí)現(xiàn)了 EventListener 接口的對(duì)象,或者是一個(gè)函數(shù)。有關(guān)回調(diào)本身的詳細(xì)信息,請(qǐng)參閱事件監(jiān)聽(tīng)回調(diào)
options 可選
一個(gè)指定有關(guān) listener 屬性的可選參數(shù)對(duì)象??捎玫倪x項(xiàng)如下:
capture 可選:一個(gè)布爾值,表示 listener 會(huì)在該類型的事件捕獲階段傳播到該 EventTarget 時(shí)觸發(fā)。once 可選:一個(gè)布爾值,表示 listener 在添加之后最多只調(diào)用一次。如果為 true,listener 會(huì)在其被調(diào)用之后自動(dòng)移除。
passive 可選:一個(gè)布爾值,設(shè)置為 true 時(shí),表示 listener 永遠(yuǎn)不會(huì)調(diào)用 preventDefault()。如果 listener 仍然調(diào)用了這個(gè)函數(shù),客戶端將會(huì)忽略它并拋出一個(gè)控制臺(tái)警告。查看使用 passive 改善滾屏性能以了解更多。
signal 可選:AbortSignal,該 AbortSignal 的 abort() 方法被調(diào)用時(shí),監(jiān)聽(tīng)器會(huì)被移除。
useCapture 可選
一個(gè)布爾值,表示在 DOM 樹(shù)中注冊(cè)了 listener 的元素,是否要先于它下面的 EventTarget 調(diào)用該 listener。
使用 passive 改善的滾屏性能
根據(jù)規(guī)范,passive 選項(xiàng)的默認(rèn)值始終為false。但是,這引入了處理某些觸摸事件(以及其他)的事件監(jiān)聽(tīng)器在嘗試處理滾動(dòng)時(shí)阻止瀏覽器的主線程的可能性,從而導(dǎo)致滾動(dòng)處理期間性能可能大大降低。
為防止出現(xiàn)此問(wèn)題,某些瀏覽器(特別是Chrome和Firefox)已將touchstart和touchmove事件的passive選項(xiàng)的默認(rèn)值更改為true文檔級(jí)節(jié)點(diǎn) Window,Document和Document.body。這可以防止調(diào)用事件監(jiān)聽(tīng)器,因此在用戶滾動(dòng)時(shí)無(wú)法阻止頁(yè)面呈現(xiàn)。
const elem = document.getElementById('elem');elem.addEventListener('touchmove', function listener() { /* do something */ }, { passive: true });
添加passive參數(shù)后,touchmove事件不會(huì)阻塞頁(yè)面的滾動(dòng)(同樣適用于鼠標(biāo)的滾輪事件)。
很多移動(dòng)端的頁(yè)面都會(huì)監(jiān)聽(tīng) touchstart 等 touch 事件,像這樣:
document.addEventListener("touchstart", function(e){... // 瀏覽器不知道這里會(huì)不會(huì)有 e.preventDefault()})
由于 touchstart 事件對(duì)象的 cancelable 屬性為 true,也就是說(shuō)它的默認(rèn)行為可以被監(jiān)聽(tīng)器通過(guò) preventDefault() 方法阻止,那它的默認(rèn)行為是什么呢,通常來(lái)說(shuō)就是滾動(dòng)當(dāng)前頁(yè)面(還可能是縮放頁(yè)面),如果它的默認(rèn)行為被阻止了,頁(yè)面就必須靜止不動(dòng)。但瀏覽器無(wú)法預(yù)先知道一個(gè)監(jiān)聽(tīng)器會(huì)不會(huì)調(diào)用 preventDefault(),它能做的只有等監(jiān)聽(tīng)器執(zhí)行完后再去執(zhí)行默認(rèn)行為,而監(jiān)聽(tīng)器執(zhí)行是要耗時(shí)的,有些甚至耗時(shí)很明顯,這樣就會(huì)導(dǎo)致頁(yè)面卡頓。即便監(jiān)聽(tīng)器是個(gè)空函數(shù),也會(huì)產(chǎn)生一定的卡頓,畢竟空函數(shù)的執(zhí)行也會(huì)耗時(shí)。
有 80% 的滾動(dòng)事件監(jiān)聽(tīng)器是不會(huì)阻止默認(rèn)行為的,也就是說(shuō)大部分情況下,瀏覽器是白等了。所以,passive 監(jiān)聽(tīng)器誕生了,passive 的意思是“順從的”,表示它不會(huì)對(duì)事件的默認(rèn)行為說(shuō) no,瀏覽器知道了一個(gè)監(jiān)聽(tīng)器是 passive 的,它就可以在兩個(gè)線程里同時(shí)執(zhí)行監(jiān)聽(tīng)器中的 JavaScript 代碼和瀏覽器的默認(rèn)行為了。
