为什么不把Javascript事件委托带到极致?

mac*_*ost 18 javascript javascript-events

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

$("#someTable TD.foo").click(function(){
    $(e.target).doSomething();
});
Run Code Online (Sandbox Code Playgroud)

将会比以下情况更糟糕:

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

现在有多糟糕将取决于你的桌子有多少TD,但只要你有至少几个TD,这个一般原则应该适用.(注意:当然,聪明的事情是使用jQuery委托而不是上面的代码,但我只是试图用明显的区别来做一个例子).

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

显然使用委托策略意味着重新思考如何阻止事件,这是一个缺点.此外,假设你有一个页面,你有一个"TD.foo",不应该有一个事件连接到它.但是,如果您理解并愿意解决事件冒泡变化,并且如果您执行"如果您将.foo放在TD上,它始终会将事件连接起来"的策略,那么这些似乎都不是很重要.

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

jfr*_*d00 22

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

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

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

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

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

在上面的例子中,完全合理的做法是:

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

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

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

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

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

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