昨日,土豆的前端开发人员们就事件侦听之间是否应该出现逻辑关联展开了一场辩论。具体争论的问题如下:
document.body.addEventListener("click", functionA, false);
document.body.addEventListener("click", functionB, false);
functionA() {
document.body.removeEventListener("click", functionB, false);
}
functionB() {
}
此时如果我在页面的body上点击了一下,会发生什么?回答有两种:A和B都执行、但下一次点击B不会再被执行了;A执行B不被执行、且以后B都不会执行。
答案是什么并不重要,关键是要看浏览器的js引擎如何处理事件侦听。分别假设上面两种答案都是正确的话,那么它们各自的处理方式应该如下:
- 点击触发后,A和B方法同时收到侦听并触发,此时它们是并行的。因此都会产生调用并存入内存队列中,等待出列执行。
- 点击触发后,A由于先注册所以先触发侦听,B完全没有任何反应,此时它们是串行的。因此A先进入队列,执行过程中移除了B的侦听,B也就永远销声匿迹了。
那么我们常见的浏览器中的js引擎都是如何实现的呢?因为js是函数式单线程的,所以正确答案是第2个。但是包括标准推荐的做法在内,我的观点是不应该在事件侦听中出现逻辑关联,也就是耦合。
如果两个事件侦听出现了依赖逻辑互相确定执行的话,那么它们本身就应该写在一个事件侦听里面,然后通过重构相分离。依然以上面的为例,B方法的执行依赖于A方法中的某个逻辑的话,更好的做法应该是这样:
document.body.addEventListener("click", listener, false);
function listener() {
if(A()) return;
B();
}
functionA() {
if(/*某个条件达成*/) return true;
return false;
}
functionB() {
}
如果出现了不同事件侦听有逻辑关联的情况的话,那么最初的设计可能就需要考虑一下。反对者(其实就是指某人)的论据则是灵活度以及js的函数式和单线程特性。在日益复杂的情势中,前端是否也应该像java摒弃多继承一样,而降低某些灵活度呢?

对于一个事件的监听函数,是不应该出现逻辑关系的