为啥不将 Javascript 事件委托发挥到极致呢?
Posted
技术标签:
【中文标题】为啥不将 Javascript 事件委托发挥到极致呢?【英文标题】:Why not take Javascript event delegation to the extreme?为什么不将 Javascript 事件委托发挥到极致呢? 【发布时间】:2012-03-31 10:51:50 【问题描述】:到目前为止,该网站上的大多数人可能都知道:
$("#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)为什么要停在那里?为什么不只为每种类型的身体本身的组成部分?”我没有一个好的答案。
显然,使用委托策略意味着重新考虑如何阻止事件,这是一个缺点。此外,假设您可能有一个页面,其中您有一个 不应该 与它挂钩的“TD.foo”。但是,如果您了解并愿意解决事件冒泡更改,并且如果您执行“如果您将 .foo 放在 TD 上,它总是会连接事件”的政策,那么这些似乎都不像大不了。
我觉得我必须遗漏一些东西,所以我的问题是:将所有站点范围组件的所有事件委托给 BODY 是否还有其他缺点(而不是将它们直接绑定到所涉及的 html 元素,或将它们委托给非 BODY 父元素)?
【问题讨论】:
我相信这是一个偏好问题和具体情况。我的意思是,您应该首先编写代码以使其尽可能易读。这样,您或其他人可以稍后进入并检查代码并轻松使用它。完成后,您可以检查代码是否运行良好并根据需要对其进行优化。在您的特定场景中, $("someTable TD.foo") 比其中包含返回的场景更易于阅读、管理和遵循。有人可能会阅读其他代码并误解它,导致他们在更改时引入错误。只是我的意见 我完全同意:开发人员应该先设计,不要担心优化,只在适当的时候再优化。然而,这一切都是出于优化现有设计的现实需求(在我们的客户决定使用成千上万行之前,我们有一个很棒的页面),所以我们试图提出最佳策略处理该优化。 Should all jquery events be bound to $(document)? 的可能重复项 【参考方案1】:你缺少的是表演的不同元素。
您的第一个示例在设置点击处理程序时性能较差,但在触发实际事件时性能更好。
您的第二个示例在设置点击处理程序时表现更好,但在触发实际事件时表现明显更差。
如果所有事件都放在***对象(如文档)上,那么您将有一个庞大的选择器列表来检查每个事件,以便找到它与哪个处理函数一起使用。这个问题就是为什么 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();
);
因为这会将表格事件与页面中的所有其他***事件混合在一起,而实际上并没有必要这样做。您只是要求事件处理中的性能问题,而没有任何处理那里的事件的好处。
因此,我认为对您的问题的简短回答是,在一个***位置处理所有事件会在触发事件时导致性能问题,因为当有很多事件时,代码必须确定哪个处理程序应该获取事件在同一个地方处理的事件。尽可能靠近生成对象处理事件,使事件处理更加高效。
【讨论】:
感谢您的详细解释。在我们正在查看的情况下(包含数万个 TD 的表),事件连接性能是瓶颈,但您的解释帮助我理解,在我们网站上的许多其他相关案例中,事件解决性能将比事件更重要连接性能(并且绑定太多文档会对分辨率性能产生负面影响)。所以......我们现在不会全局绑定所有内容:-)【参考方案2】: 如果您删除一个节点,相应的侦听器不会自动删除。 有些事件不会冒泡 不同的库可能会通过停止事件传播来破坏系统(猜你提到了那个)【讨论】:
【参考方案3】:如果您在纯 javascript 中执行此操作,则页面上任意位置的随机点击触发事件的影响几乎为零。然而,在 jQuery 中,结果可能要大得多,因为它必须运行大量的原始 JS 命令才能产生相同的效果。
就我个人而言,我发现少量委派是好的,但是过多的委派会开始导致比它解决的问题更多的问题。
【讨论】:
以上是关于为啥不将 Javascript 事件委托发挥到极致呢?的主要内容,如果未能解决你的问题,请参考以下文章