基于回调的事件处理系统和基于事件的事件处理系统有什么区别
What is difference between a callback-based and an event-based event handling system?
我正在研究一个跨浏览器的事件处理系统。我请一些开发人员审查我的代码。其中一位开发人员说,我的实现是基于回调而不是真实事件。有什么区别?
为了您的方便,我在下面提供了我的实现的源代码(也作为一个要点)。到目前为止,我还没有发现任何问题。它适用于我测试过的所有浏览器。
很抱歉对问题的糟糕描述,我不熟悉纯事件部分。
var evento = (function (window) {
var win = window
, doc = win.document
, _handlers = {}
, addEvent
, removeEvent
, triggerEvent;
addEvent = (function () {
if (typeof doc.addEventListener === "function") {
return function (el, evt, fn) {
el.addEventListener(evt, fn, false);
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt].push(fn);
};
} else if (typeof doc.attachEvent === "function") {
return function (el, evt, fn) {
el.attachEvent(evt, fn);
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt].push(fn);
};
} else {
return function (el, evt, fn) {
el["on" + evt] = fn;
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt].push(fn);
};
}
}());
// removeEvent
removeEvent = (function () {
if (typeof doc.removeEventListener === "function") {
return function (el, evt, fn) {
el.removeEventListener(evt, fn, false);
Helio.each(_handlers[el][evt], function (fun) {
if (fun === fn) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
}
});
};
} else if (typeof doc.detachEvent === "function") {
return function (el, evt, fn) {
el.detachEvent(evt, fn);
Helio.each(_handlers[el][evt], function (fun) {
if (fun === fn) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
}
});
};
} else {
return function (el, evt, fn) {
el["on" + evt] = undefined;
Helio.each(_handlers[el][evt], function (fun) {
if (fun === fn) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
_handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
}
});
};
}
}());
// triggerEvent
triggerEvent = function (el, evt) {
_handlers[el] = _handlers[el] || {};
_handlers[el][evt] = _handlers[el][evt] || [];
for (var _i = 0, _l = _handlers[el][evt].length; _i < _l; _i += 1) {
_handlers[el][evt][_i]();
}
};
return {
add: addEvent,
remove: removeEvent,
trigger: triggerEvent,
_handlers: _handlers
};
}(this));
我不能不在乎你的系统是基于回调、事件或 lambda 演算的。对于你在这里公开的那一点,它似乎写得很好,并承诺做得很好(尽管我很好奇你如何处理removeEvent()
;))。
但是,关于您的实现,我有几点意见:
- 每次添加事件处理程序时,无需检查执行的浏览器。
令我惊讶的是,每次打电话时,接受检查房产是否存在的做法的人数之多。没有人会在函数调用过程中将您的IE换成FF(如果您问我,任何愚蠢到定义实际ECMA-5替代品以外的document.addEventListener
属性的人都应该被鞭打致死),因此请检查您在开始时使用哪个平台并完成它,如下所示:
if (doc.addEventListener) {
addEvent = // ...
freeEvent = // ...
}
else if (doc.attachEvent) {
addEvent = // ...
freeEvent = // ...
}
/* etc. */
- 你提供了一个统一的接口来附加处理程序,但根据你将在其上执行代码的浏览器,实际处理程序的行为将有所不同。
例如,在 IE8- 中,事件的目标与 ECMA-5 约定中的可用方式不同。
如果要提供真正的跨浏览器界面,则应为事件处理程序提供统一的执行上下文。这可能包括一个"取消"功能,可以转换为以下内容:
cancel = function (e) { e.returnValue = false; }; // IE8-
cancel = function (e) { e.preventDefault(); }; // ECMA-5
还应将this
还原到 IE8- 下的目标对象,并统一target
和event.target
语义。
如果你真的想对程序员好,你也可以解决一些奇怪的问题,比如
- 加载事件在IE8中未触发 - 当图像已缓存时
- 荒谬复杂的鼠标滚轮报告系统
可能还有其他一些。
我出于自己的目的这样做的方式是在实际处理程序周围生成一个包装器,它可以处理所有平台特性,并在调用实际用户代码之前建立一致的执行上下文。
最后说一句:除了它的美妙之外,我不太确定是否仍然有必要支持 Netscape4 风格的活动。但这是一个信仰问题,所以...
- keyup事件处理程序更改焦点不适用于快速键入
- 提示使用服务器端事件处理程序激活JavaScript
- 将事件处理程序绑定到任何可能的事件
- 正在将事件处理程序添加到不存在的类
- dropdown.js中的复杂事件处理
- 在循环中附加事件处理程序时出现浏览器性能问题
- 在同一个javascript事件处理程序中调用不同的函数
- 复选框,然后单击事件处理
- 有没有一种方法可以让内联事件处理程序在元素创建后立即执行
- 检查事件处理程序参数
- 实现延迟的jquery更改事件处理程序
- 如何使用Node.js在JavaScript模块文件之间使用事件处理程序
- 如何使jQuery的“bind”或“on”事件处理程序幂等
- 带有参数的Javascript事件处理程序
- Jquery事件处理程序仅适用于匿名函数
- 如何从另一个处理程序内部取消JavaScript事件处理程序函数的执行
- 如何在 JavaScript 代码中调试点击事件处理
- 在大型系统中附加事件处理程序的最佳做法
- 基于回调的事件处理系统和基于事件的事件处理系统有什么区别
- 在基于事件的系统中并发地处理唯一性