使用Prototype处理点击事件时,我遇到了一个奇怪的问题。如果单击下面代码中的按钮,它将触发三个警报:“单击1”,“单击2”和“单击3”。现代浏览器将按照它们注册的顺序调用侦听器,而IE8(也可能是旧的IE版本)将以相反的顺序调用它们。我发现这很奇怪,因为我认为Prototype维护并执行了一个侦听器队列,这应该是浏览器独立的。这不是这样吗?如果没有,事件监听器是否应按某种顺序运行,或者它们是异步的,因此它们的顺序无关紧要?
<button id="button">Click me</button>
<script type="text/javascript">
$('button').observe('click', function(event) {
alert('Click 1');
});
$('button').observe('click', function(event) {
alert('Click 2');
});
$('button').observe('click', function(event) {
alert('Click 3');
});
</script>
答案 0 :(得分:15)
Prototype依赖于浏览器的订单底层触发机制(并非所有库都可以,见下文)。事件处理程序被触发的顺序最初不是由DOM事件保证的。来自DOM2 Events specification:
虽然
EventListeners
上的所有EventTarget
都可以保证由EventTarget
收到的任何事件触发,但是没有规定它们将接收的顺序有关EventListeners
上其他EventTarget
的事件。
绝大多数浏览器实施(Chrome,Firefox,Opera等),包括IE9,都会按照附加顺序触发处理程序。 IE8和更早版本以相反的方式做到了。
较新的DOM3 event spec仍然是一项正在进行中的工作,它引入了按注册顺序触发它们的要求(大多数浏览器都这样做):
接下来,实现必须确定当前目标的候选事件侦听器。这必须是已按注册顺序在当前目标上注册的所有事件侦听器的列表。
......这可能是IE9为什么会这样做的原因之一(IE9显着提高了Microsoft对事件标准的支持,添加addEventListener
等)。
一些JavaScript库(例如jQuery) do 保证订单,无论浏览器如何,每个元素每个事件只附加一个处理程序,并维护自己的用户代码处理程序列表。< / p>
答案 1 :(得分:1)
作为@ T.J的格式化评论。克劳德的答案,我测试了哪些现代浏览器实际上按照注册顺序触发了听众。
2016-10-06:结果是所有以下浏览器都这样做: chrome 53,firefox 49,safari 9,opera 40,ie 11和edge 13通过mac host上的virtualbox。
我的测试代码可以在这里找到:https://github.com/lingtalfi/browsers-behaviours/blob/master/listeners-execution-order/listeners.md
答案 2 :(得分:0)
根据这个bug report,它似乎是一个现有的错误,并且它实际上与浏览器有关。
总结报告:
它取决于浏览器,但有些用户(如海报)希望事件按顺序触发。错误条目在某一时刻被更改为文档更改(以通知用户订单实际上未指定),但错误仍然是开放的,因此我假设它尚未在文档中修复。