页面滚动不流畅,passive 你设置了吗?

516 阅读2分钟

我正在参加「掘金·启航计划」

还得从一个页面警告说起,页面里监听了 touchmove 事件,在回调中做了很多事情,导致滑动时出现卡顿,控制台给出了如下的提示 image.png 通过提示不难发现,控制台告诉我们在 touchmove 事件花费了太多时间,并指引我们设置 passive。addEventListener() 我们已经很熟悉了,用来在页面中监听事件,但是 passive 是什么?通过 MDN 我们看一下

语法

addEventListener(type, listener, options);

options

  • capture:一个布尔值,是否由捕获阶段开始传播

  • once:一个布尔值,表示只监听一次

  • signal AbortSignal 的 abort() 方法被调用时,监听器会被移除

  • passive:一个布尔值,设置为 true 时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。

重点了解下 passive

在触发一个事件的时候,浏览器并不知道用户是否会调用 preventDefault(),它需要等到事件处理函数执行完后,才能去执行默认行为,这样就会造成一定的卡顿。

在大部分页面中,我们是不会主动调用 preventDefault(),这个方法的,但是浏览器仍然会等待, 利用这一点,我们可以将 passive 设置为 true 以优化滚动的流畅度。

通过一个 gif 来对比下

12.gif

可以看到,设置 passive 的(左边),明显更流畅,未设置的(右边)滚动时会有明显的卡顿,并且控制台提示了警告。

兼容

一些旧的浏览器,仍然假定第三个参数是布尔值,所以我们需要编写一些代码来兼容,如下。

let passiveSupported = false;

try {
  const options = {
    get passive() { // 该函数会在浏览器尝试访问 passive 值时被调用。
      passiveSupported = true;
      return false;
    }
  };

  window.addEventListener("test", null, options);
  window.removeEventListener("test", null, options);
} catch (err) {
  passiveSupported = false;
}