加 passive: true 的核心是告知浏览器回调不会调用 e.preventdefault(),从而跳过等待判断、立即执行默认滚动行为以避免主线程阻塞;仅对 cancelable 为 true 且影响滚动的事件(如 touchstart/touchmove、wheel、scroll)有效。

在事件监听中加 passive: true,核心是告诉浏览器“这个回调绝不会调用 e.preventDefault()”,从而跳过等待判断,让滚动、触摸等默认行为立刻执行,避免主线程阻塞。这不是加速 JS,而是解除卡顿源头。
哪些事件加 passive 才有效
只有本身可取消(cancelable === true)且直接影响滚动行为的事件,启用 passive 才有实际意义:
- touchstart / touchmove:移动端最常见卡顿来源,哪怕空回调也会触发浏览器等待机制
- wheel:鼠标滚轮事件,Chrome 控制台出现 “Added non-passive event listener to a scroll-blocking 'wheel'” 就是它在报警
-
scroll:监听
window或带overflow: auto的容器时,高频触发易掉帧
像 click、input 这类不阻塞滚动的事件,加 passive 没效果,还可能误导后续维护者。
正确写法和典型误用
✅ 推荐写法(只读场景):
window.addEventListener('scroll', handleScroll, { passive: true });element.addEventListener('touchmove', handleTouchMove, { passive: true });
⚠️ 典型错误:设了 { passive: true } 却在回调里调用 e.preventDefault()。此时浏览器会直接忽略该调用,并报错:Unable to preventDefault inside passive event listener。这不是兼容性问题,而是强制约束——passive 就等于承诺不阻止默认行为。
如果你确实需要拦截滚动(如下拉刷新、自定义拖拽),必须:
- 只对目标区域绑定非 passive 监听器(比如仅监听下拉容器,而非整个
document) - 显式设置
passive: false或省略 options(默认就是false) - 必要时用
e.cancelable动态判断是否可取消,再决定是否调用preventDefault()
搭配其他优化更见效
passive: true 是基础,但单靠它还不够。建议组合使用:
- 节流(throttle):限制 scroll 或 touchmove 回调执行频率,避免每帧都触发
-
避免同步布局读写:不在回调里反复调用
getBoundingClientRect()或修改style.left等触发重排的属性 - 用 requestAnimationFrame 延迟视觉更新:保证主线程不被挤占
- Intersection Observer 替代滚动监听做懒加载:更轻量、更精准
removeEventListener 时不用管 passive
移除监听器时,removeEventListener 只认函数引用和事件类型,完全忽略 passive 配置项。下面两行是等价的:
element.removeEventListener('scroll', handler, { passive: true });element.removeEventListener('scroll', handler);
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











