作者:滴滴公共前端团队 - 小春
Passive Event Listeners
这个东西其实有一段时间了,关注 2016 Google I/O 的 Mobile Talk 的同学应该有些印象。
PS:
建议一些新技术方向探索的同学关注一下每一年的 Google I/O,而一般大会之后,像类似 medium 网站的一些大咖会有英文的分解。
基本我们很多技术革新或者应用产品化都会从这里面得到一些思考和启发:比如 Polymer 等。
一般新东西我都会问几个问题?
1、它有什么用?
A new feature in the
DOM spec
that enable developers to opt-in tobetter scroll performance
by eliminating the need for scrolling to block on touch and wheel event listeners.Developers can annotate
touch
andwheel
listeners with{passive: true}
to indicate that they will never invoke preventDefault.
提高页面的滑动流畅度。
PS:
FB 有一个报告:
页面滑动的响应刷新率从 60 FPS 到 30 FPS,会让用户的参与度极速下降
很多人可能对这个数据表现不是很了解,有没有比较主观的数据统计呢?
如下截图所示:
我们再回顾一下上面的那段话:
1、设置新属性
passive
2、比如在监听
mousewheel
或者touch
事件中,增加了 passive 为 true 的设置,它就不会调用 preventDefault 来阻止默认滑动行为3、或者叫:被动监听器
代码片段如下:
function handler () {
console.log('DDFE');
}
document.addEventListener('mousewheel', handler, {passive: true})复制代码
大家发现:
其实变化就是:前端 DOM 中常用常考的 addEventListener
的第三个参数:之前都是 true | false
2、兼容性?
Chrome 51 开始
Firefox 49
也已经有人做了补丁包:
大概的设计流程:
1.判断是否支持:
var supportsPassive = false;
document.createElement("div").addEventListener("test", function() {}, {
get passive() {
supportsPassive = true;
return false;
}
}
`复制代码
2.覆盖内置的 3 个原型链方法:
// 赋值默认事件原型链的 addEventListener
var super_add_event_listener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
var super_this = this;
//...
var wrapped = {
handleEvent: function (e) {
e.__passive = passive;
}
};
//...
super_add_event_listener.call(super_this, type, wrapped, useCapture);
//...
super_add_event_listener.call(super_this, type, listener, useCapture);
}复制代码
// 赋值默认事件原型链的 removeEventListener
var super_remove_event_listener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.removeEventListener = function(type, listener, options) {
var super_this = this;
//...
super_remove_event_listener.call(super_this, type, listener, useCapture);
}复制代码
// 赋值默认事件原型链的 preventDefault
var super_prevent_default = Event.prototype.preventDefault;
Event.prototype.preventDefault = function() {
// 判断是否设置了
if (this.__passive) {
console.warn("Ignored attempt to preventDefault an event from a passive listener");
return;
}
super_prevent_default.apply(this);
}复制代码
参考文献:
developers.google.com/web/updates…
medium.com/@devlucky/a… (自备梯子)
dom.spec.whatwg.org/#dom-eventl…
blog.chromium.org/2016/05/new…
stackoverflow.com/questions/3…
PS:本文插图来自 sofish 大大,感谢
欢迎关注DDFE
GITHUB:github.com/DDFE
微信公众号:微信搜索公众号“DDFE”或扫描下面的二维码