绑定父元素与直接绑定元素是否有优点或缺点



为了更好地理解jQuery的性能,我遇到了以下问题。考虑将 click 事件绑定到列表中的项的两个大致相等的解决方案:

列表项:

<div id="items">
    <div class="item"><a href="#">One</a></div>
    <div class="item"><a href="#">Two</a></div>
    <div class="item"><a href="#">Three</a></div>
</div>
<div id="items2">
    <div class="item"><a href="#">One</a></div>
    <div class="item"><a href="#">Two</a></div>
    <div class="item"><a href="#">Three</a></div>
</div>

请注意,有两个标识列表(除了 ID)。现在,考虑使用以下 jQuery 来绑定item中每个定位点的客户端事件:

$('#items').on('click', '.item a', function(e) {
   console.log("### Items click"); 
});
$('#items2 .item a').on('click', function(e) {
    console.log("### Items2 click");
});

这实现了相同的结果,因为单击列表中的项目将输出其各自的消息。

观察正在绑定的事件,在第一种情况下,单击事件被绑定到#items容器,没有事件绑定到子项。但是,在第二种情况下,没有单击事件绑定到父#items2,但每个子元素都有一个单击事件。

现在,我的问题是:一个显然比另一个更可取吗?天真,我认为第一种情况更可取,但缺乏对jQuery内部的了解,很可能两者在引擎盖下是等价的。

我准备了一个小提琴来演示这两个案例。观察jQuery为元素构建的事件,是我得出上述假设的地方(您可以在Web浏览器的控制台中看到输出)。

除非您正在处理大量元素,否则无论哪种方式都可能无关紧要。 问题是什么时候需要提高效率:在绑定时还是在触发时?

免责声明: 我不声称这些测试中的任何一个都是完美的。 另外,我只在Chrome中进行了测试。

绑定时间

我并不知道答案,所以我决定尝试测试所有内容。 首先,我假设使用委托进行绑定会快得多(它只需要绑定一次,而不是 X 次)。 这似乎是正确的。

http://jsperf.com/on-delegate-vs-not-bind-only

不委派:慢 100%

触发时间

接下来,我认为不使用委托实际上可能更快地触发事件,因为不需要 DOM 移动来检查事件触发。 无论出于何种原因,我对此都是不正确的:

http://jsperf.com/on-delegate-vs-not-trigger-pls

不委派:慢 60%

(初始.trigger是为了以防万一 jQuery 缓存委托事件,我相信它确实如此。 这将影响测试)。

仅触发一个项目

然后,我认为不使用委派会更快地触发一个特定项目的事件。 这也是错误的:

http://jsperf.com/on-delegate-vs-not-trigger-one

不委派:慢 80%

即使不是最后一个兄弟姐妹,而是早期的兄弟姐妹之一,也是如此:

http://jsperf.com/on-delegate-vs-not-trigger-one-eq2

深层嵌套

最后,我认为委派完成的很多工作都必须是 DOM 树解析。 这意味着在深度嵌套的 DOM 中使用委托并绑定到非常古老的祖先并触发比绑定到深度嵌套项本身需要更长的时间。

这最终被证明是正确的:

http://jsperf.com/on-delegate-vs-not-deep-nesting

代表:慢 90%

结论

我不能在这里得出任何巨大的结论,但是如果你有大量的 DOM 可以使用,特别是如果它是深度嵌套的,你可以看看使用委托进行绑定而不是直接绑定。

如果有的话,这些例子教会了我(好吧,无论如何都得到了加强),你应该尽量让委托元素尽可能靠近将触发事件的后代。

这就是优化的问题。让我解释一下:

$('#items2 .item a').on('click', function(e) {
  console.log("### Items2 click");
});

使用上面的代码,每个定位点都有自己的事件处理程序。这是浪费内存,因为只有一个处理程序可以执行相同的操作。

$('#items').on('click', '.item a', function(e) {
  console.log("### Items click"); 
});

同样使用第二个代码,如果在绑定后追加更多定位点以#items,则无需添加新的事件处理程序。父元素 #items 已经涵盖了它们。

最新更新