5

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

列出项目:

<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 为items 中的每个锚绑定客户端事件:

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

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

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

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

现在,我的问题是:一个明显优于另一个?天真,我认为第一种情况更可取,但由于缺乏对 jQuery 内部的了解,很可能这两种情况在幕后是等价的。

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

4

2 回答 2

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%

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

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

深层嵌套

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

这最终证明是正确的:

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

代表:慢 90​​%

结论

我不能在这里得出任何具有纪念意义的结论,但是如果您有大量的 DOM 可以使用,特别是如果它是深度嵌套的,您可能会考虑使用委托进行绑定而不是直接绑定。

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

于 2013-01-31T05:09:54.053 回答
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已经覆盖了它们。

于 2013-01-31T04:45:54.720 回答