使用 passive 改善的滚屏性能

前端精髓

共 2021字,需浏览 5分钟

 ·

2024-06-09 10:18


EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。


语法

addEventListener(type, listener);addEventListener(type, listener, options);addEventListener(type, listener, useCapture);

参数


type

表示监听事件类型的大小写敏感的字符串。


listener

当所监听的事件类型触发时,会接收到一个事件通知(实现了 Event 接口的对象)对象。listener 必须是一个实现了 EventListener 接口的对象,或者是一个函数。有关回调本身的详细信息,请参阅事件监听回调


options 可选

一个指定有关 listener 属性的可选参数对象。可用的选项如下:

capture 可选:一个布尔值,表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。once 可选:一个布尔值,表示 listener 在添加之后最多只调用一次。如果为 true,listener 会在其被调用之后自动移除。

passive 可选:一个布尔值,设置为 true 时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。查看使用 passive 改善滚屏性能以了解更多。

signal 可选:AbortSignal,该 AbortSignal 的 abort() 方法被调用时,监听器会被移除。


useCapture 可选

一个布尔值,表示在 DOM 树中注册了 listener 的元素,是否要先于它下面的 EventTarget 调用该 listener。


使用 passive 改善的滚屏性能


根据规范,passive 选项的默认值始终为false。但是,这引入了处理某些触摸事件(以及其他)的事件监听器在尝试处理滚动时阻止浏览器的主线程的可能性,从而导致滚动处理期间性能可能大大降低。


为防止出现此问题,某些浏览器(特别是Chrome和Firefox)已将touchstart和touchmove事件的passive选项的默认值更改为true文档级节点 Window,Document和Document.body。这可以防止调用事件监听器,因此在用户滚动时无法阻止页面呈现。

const elem = document.getElementById('elem');elem.addEventListener('touchmove', function listener() { /* do something */ }, { passive: true });

添加passive参数后,touchmove事件不会阻塞页面的滚动(同样适用于鼠标的滚轮事件)。


很多移动端的页面都会监听 touchstart 等 touch 事件,像这样:

document.addEventListener("touchstart", function(e){    ... // 浏览器不知道这里会不会有 e.preventDefault()})


由于 touchstart 事件对象的 cancelable 属性为 true,也就是说它的默认行为可以被监听器通过 preventDefault() 方法阻止,那它的默认行为是什么呢,通常来说就是滚动当前页面(还可能是缩放页面),如果它的默认行为被阻止了,页面就必须静止不动。但浏览器无法预先知道一个监听器会不会调用 preventDefault(),它能做的只有等监听器执行完后再去执行默认行为,而监听器执行是要耗时的,有些甚至耗时很明显,这样就会导致页面卡顿。即便监听器是个空函数,也会产生一定的卡顿,毕竟空函数的执行也会耗时。


有 80% 的滚动事件监听器是不会阻止默认行为的,也就是说大部分情况下,浏览器是白等了。所以,passive 监听器诞生了,passive 的意思是“顺从的”,表示它不会对事件的默认行为说 no,浏览器知道了一个监听器是 passive 的,它就可以在两个线程里同时执行监听器中的 JavaScript 代码和浏览器的默认行为了。

浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报