为什么不把JavaScript事件委托给极端?

到目前为止,大多数人都知道:

$("#someTable TD.foo").click(function(){ $(e.target).doSomething(); }); 

会比下面的performance要差得多:

 $("#someTable").click(function(){ if (!$(e.target).is("TD.foo")) return; $(e.target).doSomething(); }); 

现在要差多less,当然要取决于你的表有多less个TD,但是这个总体原则应该适用,只要你至less有几个TD。 (注意:当然,聪明的事情是使用jQuery代表,而不是上面的,但我只是试图做一个明显的区分例子)。

无论如何,我向同事解释了这个原则,他们的回答是:“对于站点范围的组件(例如,dateselectINPUT),为什么要停下来呢?为什么不把每个types的组件的一个处理程序绑定到BODY本身?“ 我没有一个好的答案。

显然,使用委托策略意味着重新思考如何阻止事件,所以这是一个缺点。 另外,假设你有一个页面,你有一个“TD.foo”, 不应该有一个事件挂钩。 但是,如果你明白并且愿意为事件冒泡改变而工作,并且如果你强制执行一个“如果你把TD放在.foo上,总会把事件挂钩”的策略,这些都不是大不了。

我觉得我必须错过一些东西,所以我的问题是:是否有任何其他的缺点,只是将所有站点范围组件的所有事件委托给BODY(而不是直接绑定到HTML元素,或委托他们到一个非BODY父元素)?

你缺less的是性能的不同元素。

您的第一个示例在设置点击处理程序时性能较差,但在实际事件触发时性能会更好。

你的第二个例子在设置点击处理器的时候performance更好,但是当实际的事件被触发的时候performance会更差。

如果所有的事件都放在顶层的对象上(比如文档),那么你将有一个巨大的select器列表来检查每一个事件,以便find它所处理的处理函数。 这就是为什么jQuery不赞成使用.live()方法,因为它查找文档对象上的所有事件,以及注册了.live()事件处理程序时,每个事件的执行都很糟糕,因为它必须比较每个事件到很多很多的select器来find适当的事件处理程序。 对于大规模的工作来说,将事件绑定到触发事件的实际对象更为有效。 如果对象不是dynamic的,则将事件绑定到将触发它的对象。 当您第一次绑定事件时,这可能会花费更多的CPU,但是实际的事件触发将会很快并且会缩放。

jQuery的.on().delegate()可以用于这个,但是build议你find一个尽可能接近触发对象的祖先对象。 这可以防止在一个顶级对象上形成大量dynamic事件,并防止事件处理的性能下降。

在你上面的例子中,这是完全合理的:

 $("#someTable").on('click', "td.foo", function(e) { $(e.target).doSomething(); }); 

这将给你一个紧凑的表示所有行的点击处理程序,它会继续工作,即使你添加/删除行。

但是,这不会有多less意义:

 $(document).on('click', "#someTable td.foo", function(e) { $(e.target).doSomething(); }); 

因为如果没有真正需要的话,这将会把表格事件与页面中的所有其他顶级事件混合在一起。 您只是在事件处理中要求性能问题,没有任何处理事件的好处。

所以,我认为你的问题的简短答案是,处理所有事件在一个顶级的地方导致性能问题,当事件被触发,因为代码必须清理哪个处理程序应该得到事件,当有很多事件在同一个地方处理。 尽可能接近生成对象处理事件使事件处理更加高效。

如果你用普通的JavaScript做的话,页面上随机点击触发事件的影响几乎为零。 然而,在jQuery中,由于需要运行的原始JS命令的数量会产生相同的效果,所以后果可能会更大。

就我个人而言,我发现一个小小的代表团是好的,但是太多的代表团会开始造成比解决问题更多的问题。

  • 如果删除节点,则相应的侦听器不会自动删除。
  • 有些事件只是不泡
  • 不同的图书馆可能会通过停止事件传播来破坏系统(猜你提到过那个)