IE下,事件触发那点破烂事儿
作者:lifesinger 来源:岁月如歌 时间:2009-04-27 12:31:00
* 惯,请先看测试页面:event-test.html
结论:
在非IE浏览器,同一元素同一事件类型的处理函数是先进先出的。只有IE下,是先进后出。
jQuery实现了自己的一套队列机制,用jQuery注册的事件,在IE下也是先进先出的。
可以用setTimeout脱离当前队列,排到后面去。在一定程度上,这可以解决某些问题。
在jQuery中,可以用stopImmediatePropagation方法阻止队列中的后续事件。
看起来,jQuery的处理很强大很人性化。但是,一个好的鲁棒的事件机制,我觉得应该满足以下三个特性:
独立性:在注册事件时,各个事件处理函数彼此绝缘,不知道对方的存在。
并发性:在触发事件时,各个事件处理函数是并发的,不存在顺序依赖关系。
健壮性:在触发事件后,某个事件处理函数的异常,不会影响其它事件处理函数,不会因一粒老鼠屎而坏掉一锅汤。
独立性要求我们在设计时就考虑清楚。比如以下应用场景,给链接linkA先后注册事件eventA和eventB. 在eventA里,动态生成divA. 在eventB里,需要对divA进行操作。这种设计,就让eventA和eventB产生了关联。在IE下,eventB先触发,结果就会和预期不对。一个更好的做法是,将对divA的操作,放到eventA里去,保证eventB不依赖eventA。当然,实际情况比我们想象中的复杂,比如eventA可能是第三方代码,我们无权修改。这时,采用事件代理,将eventB注册到linkA的父级容器里去,能保证eventB在eventA之后执行。但这依旧取决于第三方代码的写法,比如在第三方代码里可能停止了事件冒泡。对于事件的依赖,没有完美的解决方案。最好的做法就是,从一开始就尽量让各个事件处理函数保持独立性。
因为JavaScript的单线程特性,并发目前是做不到的。作为一个良好的思维习惯,我们可以认为JavaScript的事件触发是并发的。这样,不独立都不行。独立性的重要性也就不言而喻了。注:setTimeout可以让当前函数在线程中重新排队,但某种程度上属于hack,不可滥用。
在YUI和MooTools中,当一个事件处理函数异常时,不会影响其它事件处理函数(实现方式很简单,就是try catch)。但在jQuery 1.3.2中,如果一个事件处理处理函数异常,剩下的函数都不会执行了。健壮性能让独立性真正发挥作用,也是并发性的保障。在框架级代码中得特别留意。
结论的结论
保持独立性很重要。无论做人,还是写代码。