一个跨浏览器事件检查的反思

本文介绍两种提高事件处理效率的方法:延迟加载与预加载,并提供了一段详细的JavaScript代码示例,展示了如何通过这两种方法来减少不必要的运行时检查,从而提升代码性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般的事件检查代码如下:

function addHandler(target, eventType, handler) { if (target.addEventListener) { target.addEventListener(eventType, handler, false); } else { target.attachEvent("on" + eventType, handler); } } function removeHandler(target, eventType, handler) { if (target.removeEventListener) { target.removeEventListener(eventType, handler, false); } else { target.detachEvent("on" + eventType, handler); } }


乍一看,这些函数为实现他们的目的已经足够优化。影藏的性能问题在于每次函数调用时都执行重复工作。每次都进行同样的检查,看看某种方法是否存在。如果addHandler

以上连就调用addEventListener那么每个后续调用都要出现这句代码。

解决方案一:延迟加载:

function addHandler(target, eventType, handler) { if (target.addEventListener) { addHandler = function (target, eventType, handler) { target.addEventListener(eventType, handler, false); }; } else { addHandler = function (target, eventType, handler) { target.attachEvent("on" + eventType, handler); }; } addHandler(target, eventType, handler); } function removeHandler(target, eventType, handler) { if (target.removeEventListener) { removeHandler = function (target, eventType, handler) { target.removeEventListener(eventType, handler, false); }; } else { removeHandler = function (target, eventType, handler) { target.detachEvent("on" + eventType, handler); }; } removeHandler(target, eventType, handler); }


这两个方法第一次被调用时,检查一次并决定适用那种方法附加或分离句柄。然后,原始函数就被包含适当操作的新函数覆盖了。最后调用新函数并将原始参数传给他。

调用一个延迟加载函数总是在第一次使用较长时间,因为它必须运行监测然后调用另一个函数已完成任务。但是,后续调用同一函数将快很多,因为不再执行检查逻辑了。

延迟加载适用于函数不会在页面上立即被用到的场合。

解决方案二:预加载

var addHandler = document.body.addEventListener ? function (target, eventType, handler) { target.addEventListener(eventType, handler, false); } : function (target, eventType, handler) { target.attachEvent("on" + eventType, handler); }; var removeHandler = document.body.removeEventListener ? function (target, eventType, handler) { target.removeEventListener(eventType, handler, false); } : function (target, eventType, handler) { target.detachEvent("on" + eventType, handler); };


它在脚本加载前进行检查,而不等待函数调用。这样做检查仍然只是一次,但此过程中来的更早。预加载适用于一个函数马上就会用到,而且在整个页面生命周期中经常使用的场合

在这里强调一下2级事件虽然支持事件捕获和事件冒泡,但是addEventListener、removeEventListener中第三个参数为 false表示支持事件冒泡,为true表示支持事件捕获

同时这里也把Dean Edwards写的addEvent库的代码给出来一共大家参考

function addEvent(element, type, handler) { if (!handler.$$guid) { //为每个事件处理函数赋予一个独立的ID handler.$$guid = addEvent.guid++; } if (!element.events) { //为元素建立一个事件类型散列表 element.events = {}; } //为每个元素、事件建立一个事件处理函数散列表 var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; if (element["on" + type]) { handlers[0] = element["on" + type]; } } handlers[handler.$$guid] = handler; element["on" + type] = handleEvent; } //创建独立ID的计数器 addEvent.guid = 1; function removeEvent(element, type, handler) { if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } } function handleEvent(event) { var returnValue = true; event = event || fixEvent(window.event);//获取事件对象 var handlers = this.events[event.type];//获取书剑处理函数散列表引用 for (var i in handlers) { this.$$handleEvent = handlers[i]; if (this.$$handleEvent(event) === false) { returnValue = false; } } return returnValue; }; function fixEvent(event) { event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; }; fixEvent.preventDefault = function () { this.returnValue = false; }; fixEvent.stopPropagation = function () { this.cancelBubble = true; } /*调用示例 addEvent(document.getElementsByTagName("div")[0], "click", function () { alert("ok"); removeEvent(this, "click", arguments.callee); }); */


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值