为什么不将JavaScript事件委托发挥到极致呢?

9gm1akwq  于 2023-01-24  发布在  Java
关注(0)|答案(3)|浏览(76)

到目前为止,这个网站上的大多数人可能已经意识到:

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

会比以下情况差得多:

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

当然,情况恶化到什么程度取决于您的表有多少个TD,但是只要您至少有几个TD,这个一般原则就应该适用。(注意:当然,明智的做法是使用jQuery委托,而不是上面的委托,但我只是想做一个有明显区别的示例)。
无论如何,我向一位同事解释了这个原则,他们的回答是“嗯,对于站点范围的组件(例如,日期选择INPUT),为什么到此为止呢?为什么不将每种类型的组件的一个处理程序绑定到BODY本身呢?”我没有一个好的答案。
显然,使用委托策略意味着重新考虑如何阻止事件,这是一个缺点。此外,假设您有一个“TD.foo“页面,该页面 * 不应该 * 有事件连接到它。但是,如果您理解并愿意解决事件冒泡变化,并且如果您执行“如果您在TD上放置.foo,它总是会得到事件挂钩”,这两个似乎都不是什么大事。
我觉得我一定错过了什么,所以我的问题是:仅仅将所有站点范围组件的所有事件委托给BODY(与将它们直接绑定到相关的HTML元素或将它们委托给非BODY父元素相反)是否还有其他缺点?

aij0ehis

aij0ehis1#

你错过的是表演中有不同的元素。
第一个示例在设置单击处理程序时性能较差,但在触发实际事件时性能较好。
第二个示例在设置单击处理程序时性能较好,但在触发实际事件时性能明显较差。
如果所有事件都放在顶级对象上(就像文档),那么您将有一个巨大的选择器列表来检查每个事件,以便找到它与哪个处理函数相匹配。这个问题正是jQuery反对.live()方法的原因,因为它查找文档对象上的所有事件,并且当注册了许多.live()事件处理程序时,每个事件的性能都很差,因为它必须将每个事件与大量的选择器进行比较,以便为该事件找到合适的事件处理程序。对于大规模的工作,将事件绑定到触发该事件的实际对象附近会非常非常有效。如果对象不是动态的,然后将事件直接绑定到将触发它的对象上。这可能会在首次绑定事件时多消耗一点点CPU,但实际的事件触发将很快,而且会扩展。
jQuery的.on().delegate()可以用于此目的,但建议您找到一个尽可能接近触发对象的祖先对象,这可以防止在一个顶级对象上累积大量动态事件,并防止事件处理的性能下降。
在上面的例子中,这样做是完全合理的:

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

这将为所有行给予一个紧凑的单击处理程序表示,并且即使添加/删除行,它也将继续工作。
但是,这并没有多大意义:

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

因为这会在真实的上不需要这样做时将表事件与页面中的所有其他顶级事件混合在一起。您只是在事件处理中询问性能问题,而没有从处理那里的事件中获得任何好处。
所以,我认为你的问题的简短答案是,在一个顶级位置处理所有事件会导致当事件被触发时的性能问题,因为代码必须在同一个位置处理大量事件时挑选出哪个处理程序应该获得事件。尽可能靠近生成对象处理事件会使事件处理更有效。

h79rfbju

h79rfbju2#

如果使用纯JavaScript,则页面上任意位置的随机点击触发事件的影响几乎为零,而在jQuery中,由于要产生相同效果必须运行大量原始JS命令,因此影响可能会更大。
就我个人而言,我认为一点授权是好的,但是太多的授权会引起比它解决的问题更多的问题。

wsxa1bj1

wsxa1bj13#

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

相关问题