为什么不把Javascript事件委托带到极致? [英] Why not take Javascript event delegation to the extreme?

查看:96
本文介绍了为什么不把Javascript事件委托带到极致?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  $(#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,不应该有一个事件连接到它。但是,如果您理解并愿意解决事件冒泡变化,并且如果您执行如果您将.foo放在TD上,它始终会将事件连接起来的策略,那么这些似乎都不是我觉得我必须遗漏一些东西,所以我的问题是:将所有站点范围的组件的所有事件委派给所有事件还有其他任何缺点吗? BODY(而不是将它们直接绑定到所涉及的HTML元素,或者将它们委托给非BODY父元素)?

解决方案

你缺少的是性能有不同的元素。



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



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



如果发生了所有事件顶级对象(如文档),然后你会有一个巨大的选择器列表来检查每个事件,以便找到它所处理的处理函数。这个问题是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();
} );

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



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


By now most folks on this site are probably aware that:

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

is going to perform much worse than:

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

Now how much worse will of course depend on how many TDs your table has, but this general principle should apply as long as you have at least a few TDs. (NOTE: Of course the smart thing would be to use jQuery delegate instead of the above, but I was just trying to make an example with an obvious differentiation).

Anyhow, I explained this principle to a co-worker, and their response was "Well, for site-wide components (eg. a date-picking INPUT) why stop there? Why not just bind one handler for each type of component to the BODY itself?" I didn't have a good answer.

Obviously using the delegation strategy means rethinking how you block events, so that's one downside. Also, you hypothetically could have a page where you have a "TD.foo" that shouldn't have an event hooked up to it. But, if you understand and are willing to work around the event bubbling change, and if you enforce a policy of "if you put .foo on a TD, it's ALWAYS going to get the event hooked up", neither of these seems like a big deal.

I feel like I must be missing something though, so my question is: is there any other downside to just delegating all events for all site-wide components to the BODY (as opposed to binding them directly to the HTML elements involved, or delegating them to a non-BODY parent element)?

解决方案

What you're missing is there are different elements of the performance.

Your first example performs worse when setting up the click handler, but performs better when the actual event is triggered.

Your second example performs better when setting up the click handler, but performs significantly worse when the actual event is triggered.

If all events were put on a top level object (like the document), then you'd have an enormous list of selectors to check on every event in order to find which handler function it goes with. This very issue is why jQuery deprecated the .live() method because it looks for all events on the document object and when there were lots of .live() event handlers registered, performance of each event was bad because it had to compare every event to lots and lots of selectors to find the appropriate event handler for that event. For large scale work, it's much, much more efficient to bind the event as close to the actual object that triggered the event. If the object isn't dynamic, then bind the event right to the object that will trigger it. This might cost a tiny bit more CPU when you first bind the event, but the actual event triggering will be fast and will scale.

jQuery's .on() and .delegate() can be used for this, but it is recommended that you find to an ancestor object that is as close as possible to the triggering object. This prevents a buildup of lots of dynamic events on one top level object and prevents the performance degradation for event handling.

In your example above, it's perfectly reasonable to do:

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

That would give you one compact representation of a click handler for all rows and it would continue to work even as you added/removed rows.

But, this would not make as much sense:

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

because this would be mixing the table events in with all other top level events in the page when there is no real need to do that. You are only asking for performance issues in the event handling without any benefit of handling the events there.

So, I think the short answer to your question is that handling all events in one top level place leads to performance issues when the event is triggered as the code has to sort out which handler should get the event when there are a lot of events being handled in the same place. Handling the events as close to the generating object as practical makes the event handling more efficient.

这篇关于为什么不把Javascript事件委托带到极致?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆