绑定父元素与元素直接相比有优缺点吗?

时间:2013-01-31 04:22:01

标签: javascript jquery performance

为了更好地理解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");
});

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

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

现在,我的问题是:明显优于另一个?天真,我认为第一种情况更可取,但缺乏对jQuery内部的了解,很可能是很可能这两者在引擎盖下相当。

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

2 个答案:

答案 0 :(得分:8)

除非你正在处理大量的元素,否则两种方式都无关紧要。问题是 何时需要更高效:在绑定时或触发时?

免责声明: 我并不认为任何这些测试都是完美的。另外,我只在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%

即使不是 last 兄弟,也是早期兄弟姐妹之一,这是如此:

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

深度嵌套

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

这最终证明是正确的:

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

委托:慢90%

结论

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

如果有的话,这些例子已经教会了我(好吧,无论如何都强化了)你应该尝试让委托元素尽可能接近将触发事件的后代。

答案 1 :(得分:3)

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

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

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

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

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