IE对事件监听程序的”胡乱执行”
Time: 10-05-1 Comments: 14
今天,有个同事遇到这样的问题:IE下,给某个事件添加多个监听程序,在事件被激活时,监听程序没有按照添加顺序执行,但其他浏览器下却会按序执行,杯具。。。
一. 示例
// 基于YUI
var E = YAHOO.util.Event;
E.on(document, 'click', function() {
alert(1);
});
E.on(document, 'click', function() {
alert(2);
});
E.on(document, 'click', function() {
alert(3);
});
我机器上(winxp),各浏览器下的显示顺序:
(1) IE6:2,3,1
(2) IE7/8:3,2,1
(3) 非IE:1,2,3
二. 相关资料
在msdn上找到了一份关于attachEvent方法的官方说明,文章的Remarks部分对上例中的问题作出了说明:
If you attach multiple functions to the same event on the same object, the functions are called in random order, immediately after the object's event handler is called. 从官方说明中,可以了解到两点: (1) 通过attachEvent添加的事件监听程序,在事件激活时,是被随机执行的(不过这解释不了IE7/8下的情况,明显就是倒序执行,这也叫随机,MD。。。); (2) 通过attachEvent添加的事件监听程序,其激活顺序位于event handler(直接作为对象属性存在,如el.onclick = handler;)之后。
三. 验证一下第”2″点
// Test_1:event handler出现在event notify前面
var E = YAHOO.util.Event;
document.onclick = function() {
alert('handler');
}
E.on(document, 'click', function() {
alert('notify');
});
显示顺序:
(1) IE6/7/8:'handler' -> 'notify'
(2) 非IE:'handler' -> 'notify'
// Test_2:event handler出现在event notify后面
var E = YAHOO.util.Event;
E.on(document, 'click', function() {
alert('notify');
});
document.onclick = function() {
alert('handler');
}
显示顺序:
(1) IE6/7/8:'handler' -> 'notify'
(2) 非IE:'notify' -> 'handler'
IE果然如他宣称的,”after the object’s event handler is called”;非IE则不管这些,执行顺序完全取决于监听程序的添加顺序!
网上有文章提到:jQuery中添加事件监听的方法解决了IE的问题(都是按添加顺序执行),这个有待验证,但可以确定的是YUI 2.7和2.8未解决该问题。

Comments
lenel at 2010年05月1日 8:32 上午
用唯一的开放的事件代理是可以解决这个问题的.还能减少事件注册数.jquery就是封装到了统一的事件注册程序当中了.
jquery作者的书里说ie是倒序,没想到ie6是乱序…老外还有个封装事件注册函数的比赛,呵呵.真是有功夫…
释然 at 2010年05月3日 11:42 上午
偶有一点很奇怪,为什么document.click没有把之前E.on的事件覆盖掉???
释然 at 2010年05月3日 12:18 下午
所以,偶猜测,document.onclick会优于E.on先解析
释然 at 2010年05月3日 12:31 下午
要么就是document.onclick不会覆盖E.on添加的事件?。。。很奇怪。。
释然 at 2010年05月3日 12:50 下午
尝试下更为怪异的情况
document.onclick = function() {
alert(‘cecilia’);
}
E.on(document, ‘click’, function() {
alert(‘notify’);
});
document.onclick = function() {
alert(‘handler’);
}
E.on(document, ‘click’, function() {
alert(‘jolin’);
});
与
E.on(document, ‘click’, function() {
alert(‘notify’);
});
document.onclick = function() {
alert(‘handler’);
}
E.on(document, ‘click’, function() {
alert(‘jolin’);
});
注意Firefox、ie、Opera的区别。。。Firefox下的情况会让你很不理解~
释然 at 2010年05月3日 12:51 下午
哥研究下啊,回头跟我讲讲,哥去吃饭了,饿死了~
Author comment by Tcer at 2010年05月3日 12:55 下午
@lenel,求’封装事件注册函数的比赛’的文章出处。。。
Author comment by Tcer at 2010年05月3日 12:57 下午
@释然,官方说明中有提到: document.onclick和E.on的执行顺序是,先document.onclick,后E.on
释然 at 2010年05月3日 2:07 下午
@天 有没有文档给看一下。。
lenel at 2010年05月3日 8:50 下午
YUI用的不多,竟然没有统一事件顺序.很遗憾…
@Tcer, 应该是John Resig的’精通JS’里提到的.受到表扬的是dean edwards.查了下:
http://dean.edwards.name/weblog/2005/10/add-event/
龙藏 at 2010年05月4日 11:15 上午
如果有顺序执行的话 当满足以下条件时,不如标记下堆到队列里。
1。已知事件顺序。
2。可传递事件数据。
3。事件执行是连续的。
那么可以根据最后一个事件完成后依次执行队列。虽然可能有那么一点点什么的。。。。
Tweets that mention IE对事件监听程序的”胡乱执行” - 哈哈小老虎's Blog -- Topsy.com at 2010年05月4日 3:14 下午
[...] This post was mentioned on Twitter by 南芝 && 释然. 南芝 && 释然 said: 求解:http://www.mytcer.com/607 [...]
传统事件注册模式在FF中的怪异表现 - 哈哈小老虎's Blog at 2010年05月4日 10:04 下午
[...] 在上一篇文章的评论中,释然提出了一个很有趣的问题,查阅了一些资料,这里分享下。。。 [...]
Bruce at 2010年05月22日 1:11 下午
如果有顺序执行的话 当满足以下条件时,不如标记下堆到队列里。
1。已知事件顺序。
2。可传递事件数据。
3。事件执行是连续的。
那么可以根据最后一个事件完成后依次执行队列。虽然可能有那么一点点什么的。。。。