控制台报错 -- 被动事件监听器 !!!

13,751 阅读5分钟

前言

在线上项目运行时控制台出现 警告 信息,这太令人抓狂了,

虽然是个警告不足以影响项目的运行,但是出于本人的洁癖,小小的警告都看着十分不爽,那借此机会来优化一下吧!

image.png

被动事件监听器

项目中出现了以下报错,初步判断是由于大屏上使用了地图组件的原因,地图的放大、平移等功能触发了事件监测。

那么先看看这报错是什么:

[Violation] Added non-passive event listener to a scroll-blocking <some> event. Consider marking event handler as 'passive' to make the page more responsive. See <URL>

[违规] 添加非被动事件监听器到滚动阻塞 'touchstart' 事件。 考虑将事件处理程序标记为“passive”,以使页面响应更快。

出现报错的原因:Chrome51 版本以后,Chrome 增加了新的事件捕获机制-Passive Event Listeners;

Passive Event Listeners:被动事件侦听器是 DOM 规范中的一项新功能,它使开发人员能够通过消除滚动来阻止触摸和滚轮事件侦听器来选择加入以获得更好的滚动性能。

开发人员可以使用 {passive: true} 来设置监听器后内部不会调用 preventDefault() 来阻止默认滑动行为,Chrome 浏览器称这类型的监听器为被动(passive)监听器。

Passive Event Listeners 就是告诉前页面内的事件监听器内部是否会调用 preventDefault 函数来阻止事件的默认行为,以便浏览器根据这个信息更好地做出决策来优化页面性能。

目前Chrome主要利用该特性来优化页面的滑动性能,所以Passive Event Listeners特性当前仅支持mousewheel/touch相关事件。

解决方案:

设置事件侦听器的 passive 属性

可以通过在事件侦听器的第三个参数中添加 passive: true 来解决它。

在注册事件监听器的时候指定“passive: true”,事件处理程序不会调用 preventDefault 来阻止默认滑动行为

此声明允许浏览器在检查之前开始滚动,从而提高滚动性能。

要使用此选项,请将 {passive: true} 指定为 addEventListener() 的第三个参数。

document.addEventListener ( 'touchstart' , handler, { passive: true } ) ;

检测浏览器是否可以使用被动监听

如果你只想支持最新的浏览器,你可以通过指定 {passive: true} 作为事件监听器的第三个参数来实现,

但如果你想支持旧的浏览器那么需要提前对浏览器进行检测判断。

// 通过选项对象中的 getter 进行测试,以查看是否访问了被动属性
var supportsPassive = false;
try {
  var opts = Object.defineProperty({}, 'passive', {
    get: function() {
      supportsPassive = true;
    }
  });
  window.addEventListener("testPassive", null, opts);
  window.removeEventListener("testPassive", null, opts);
} catch (e) {}

通过监测的结果设置监听器的 passive 属性

document.addEventListener('touchstart', fn, supportsPassive ? { passive: true } : false); 

安装 default-passive-events 包

在项目中安装 default-passive-events,并引入 main.js 中,

这个包的作用是通过添加 passive,来阻止 touchstart 事件,让页面更加流畅。

1. yarn add default-passive-events  // 安装 

2. import "default-passive-events";	 // main.js 中引入

在项目中尝试安装 default-passive-events 包的方法 亲测有效,可以放心 大胆的用 !!!

触摸或滚轮事件

在某些情况下,开发者可能有意希望通过取消所有触摸或滚轮事件来始终禁用滚动。这些包括:

  • 平移和缩放地图
  • 全页/全屏游戏

在这些情况下,当前行为(阻止滚动优化)是完全足够的,因为滚动本身一直被阻止。在这些情况下不需要使用被动侦听器,尽管应用 touch-action: none 通过 CSS 规则来明确你的意图是一个好主意(例如,支持具有指针事件但不支持触摸事件的浏览器)。

然而,在一些常见的场景中,事件不需要阻止滚动——例如:

  • 用户活动监控,只想知道用户上次活动的时间
  • touchstart隐藏一些活动 UI 的处理程序(如工具提示)
  • touchstart以及touchend设置 UI 元素样式的处理程序(不抑制click事件)。

被动监听器的作用

防止滚动垃圾

滚动垃圾(scroll hijacking)是指在网页滚动时,页面的滚动行为被人为地干扰或改变,通常会导致用户体验变差。当用户滚动页面时,页面可能会在某个位置突然卡住,或者滚动速度忽快忽慢,这都会给用户带来困惑和不适,影响用户的体验感。

而这种滚动卡顿的主要原因是等待 Javascript 处理。

在使用普通的事件监听器时,当浏览器接收到滚动事件时,会等待JavaScript引擎是否会调用preventDefault()方法来决定是否阻止默认行为,这会导致页面滚动的性能和响应变差。

而使用被动监听器时,浏览器不再等待JavaScript引擎来决定是否调用 preventDefault() 方法来阻止触发事件的默认行为,从而提升页面的滚动性能。,从而能够更快地响应滚动事件,提升页面的滚动性能。

总结

当一个页面出现严重的滚动卡顿时,它总是表明某处存在潜在的性能问题。被动事件侦听器无法解决这些潜在问题,需要通过减少和分解长时间运行的 JS ,避免滚动垃圾,以提高用户体验。

参考

  1. 让页面滑动流畅得飞起的新特性