为什么不把 Javascript 事件委托发挥到极致呢?

IT技术 javascript javascript-events
2021-02-16 19:35:53

到目前为止,本网站上的大多数人可能都知道:

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

将比以下表现差得多:

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

现在有多糟糕当然取决于你的表有多少个 TD,但只要你至少有几个 TD,这个一般原则就应该适用。(注意:当然,聪明的做法是使用 jQuery 委托而不是上面的,但我只是想举一个有明显区别的例子)。

无论如何,我向一位同事解释了这个原则,他们的回答是“好吧,对于站点范围的组件(例如日期选择输入),为什么要停在那里?为什么不为每种类型的组件绑定一个处理程序到身体本身?” 我没有很好的答案。

显然,使用委托策略意味着重新思考如何阻止事件,所以这是一个缺点。此外,假设您可能有一个页面,其中有一个“TD.foo”,它不应该有一个事件与之相关联。但是,如果您理解并愿意解决事件冒泡更改,并且如果您执行“如果您将 .foo 放在 TD 上,它总是会连接事件”的策略,那么这些似乎都不是大不了。

我觉得我一定遗漏了一些东西,所以我的问题是:将所有站点范围内的所有组件的所有事件委托给 BODY(而不是将它们直接绑定到所涉及的 HTML 元素,或者将它们委托给它们)还有其他不利之处吗?到非 BODY 父元素)?

3个回答

您缺少的是性能的不同元素。

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

您的第二个示例在设置点击处理程序时表现更好,但在触发实际事件时表现明显更差。

如果所有事件都放在一个顶级对象(如文档)上,那么您将有一个庞大的选择器列表来检查每个事件,以便找到它使用的处理程序函数。这个问题就是 jQuery 弃用该.live()方法的原因,因为它会查找文档对象上的所有事件,并且当有很多事件时.live()事件处理程序注册后,每个事件的性能都很糟糕,因为它必须将每个事件与大量选择器进行比较,才能为该事件找到合适的事件处理程序。对于大规模的工作,将事件绑定到尽可能接近触发事件的实际对象的效率要高得多。如果对象不是动态的,则将事件权限绑定到将触发它的对象。当您第一次绑定事件时,这可能会花费更多的 CPU,但实际的事件触发会很快并且会扩展。

jQuery's.on().delegate()可以用于此,但建议您找到尽可能接近触发对象的祖先对象。这可以防止在一个顶级对象上积累大量动态事件,并防止事件处理的性能下降。

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

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

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

但是,这没有多大意义:

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

因为当没有真正需要这样做时,这会将表事件与页面中的所有其他顶级事件混合在一起。您只是在事件处理中询问性能问题,而没有在那里处理事件的任何好处。

因此,我认为对您的问题的简短回答是,在触发事件时,在一个顶级位置处理所有事件会导致性能问题,因为当有很多事件发生时,代码必须找出哪个处理程序应该获取该事件在同一个地方处理。尽可能靠近生成对象处理事件使事件处理更有效。

谢谢你这么详细的解释。在我们查看的情况下(包含数万个 TD 的表),事件连接性能是瓶颈,但您的解释帮助我理解,在我们网站上的许多其他相关案例中,事件解决性能比事件更重要连接性能(和文档绑定太多会对该分辨率性能产生负面影响)。所以......我们现在不会全局绑定所有内容:-)
2021-04-20 19:35:53

如果您使用纯 JavaScript 执行此操作,则页面上任意位置的随机点击触发事件的影响几乎为零。然而,在 jQuery 中,由于必须运行大量原始 JS 命令才能产生相同的效果,因此结果可能会更大。

就我个人而言,我发现一个小的委托是好的,但是过多的委托会开始引起比解决的问题更多的问题。

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