对父元素与元素直接绑定有好处或坏处吗?

时间:2022-12-09 21:49:32

In an effort to better understand jQuery performance, I've come across the following question. Consider the two approximately equal solutions for binding a click event to items in a list:

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

List items:

列表项:

<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>

Notice there are two idential lists (aside from the ID). Now, consider the following jQuery to bind the client events for each of the anchors in the items:

注意,除了ID外,还有两个idential列表。现在,考虑下面的jQuery,为项目中的每个锚点绑定客户端事件:

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

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

This achieves the same result in that clicking on items in the lists will output their respective message.

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

Observing the events that are being bound, in the first case, a click event is being bound to the #items container, with no events being bound to the children. However, in the second case, no click event is being bound to the parent #items2, but each of the children elements has a click event.

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

Now, my question is: is one clearly preferable over the other? Being naive, I would assume the first case is preferable, but lacking knowledge of the internals of jQuery, it may very well be likely that the two are equivalent under-the-hood.

现在,我的问题是:一个明显比另一个更好吗?出于天真,我认为第一种情况更可取,但由于不了解jQuery的内部原理,这两种情况很可能是相同的。

I've prepared a fiddle to demonstrate the two cases. Observing the events that jQuery has built for the elements, is where I derived the above assumptions (you can see output in your web browser's console).

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

2 个解决方案

#1


8  

Unless you are dealing with some huge number of elements, it probably does not matter either way. The question is when do you need to be more efficient: at bind time or at trigger time?

除非你要处理大量的元素,否则这两种方法都没有关系。问题是,什么时候需要更高效:在绑定时还是在触发时?

Disclaimer: I don't claim that any of these tests are perfect. Also, I only tested in Chrome.

免责声明:我不认为这些测试是完美的。另外,我只测试了Chrome。

Binding time

I didn't know the answer offhand, so I decided to just try and test everything out. First, I assumed that using delegation would be a lot faster for binding (it only has to bind once as opposed to X number of times). This appears to be correct.

我当时不知道答案,所以我决定试着把所有的东西都试一试。首先,我假设使用委托进行绑定要快得多(只需绑定一次,而不必绑定X次)。这似乎是正确的。

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

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

Do not delegate: 100% slower

不要委托:100%慢

Trigger time

Next, I figured that not using delegation may actually be faster for triggering the events because no DOM movement is needed to check event triggering. For whatever reason, I was incorrect about that:

接下来,我认为不使用委托可能会更快地触发事件,因为不需要通过DOM移动来检查事件触发。无论出于什么原因,我对此的看法是错误的:

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

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

Do not delegate: 60% slower

不委派:60%慢?

(The initial .trigger is done just in case jQuery caches delegated events, which I believe it does. This would impact the test).

(最初的.trigger是在jQuery缓存委托事件时执行的,我认为它是这样做的。这将影响测试。

Triggering only one item

Then, I figured that not using delegation would be faster for triggering the event on one specific item. This too was wrong:

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

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

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

Do not delegate: 80% slower

不委派:慢80%

This is so even if it's not the last sibling, but one of the earlier siblings:

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

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

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

Deep Nesting

Finally, I figured that a lot of the work done by delegation has to be DOM tree parsing. That means that using delegation in a deeply nested DOM and binding to a very old ancestor and triggering takes longer than binding to and triggering on the deeply nested item itself.

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

This finally turned out to be correct:

这最终被证明是正确的:

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

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

Delegate: 90% slower

代表:慢90%

Conclusion

I can't draw any monumental conclusions here, but if you have a ton of DOM to work with, especially if it's deeply nested, you might take a look at using delegation for binding rather than binding directly.

这里我不能得出任何不朽的结论,但是如果您需要处理大量的DOM,特别是如果它是嵌套的,那么您可以考虑使用委托进行绑定,而不是直接绑定。

If anything, these examples have taught me (well, reinforced anyway) that you should try to keep the delegating element as close to the descendants that will trigger the event as possible.

如果有什么不同的话,这些例子告诉我(好吧,不管怎样,加强了),您应该尽量让委托元素与触发事件的子元素保持尽可能近的距离。

#2


3  

That's the matter of optimization. Let me explain:

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

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

With the above code, each and every anchor have own event handler. It's waste of memory because just a single handler can do same action.

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

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

Also with the second code, if you append more anchors to #items after binding, you don't need to add new event handler. The parent element, #items, cover them already.

对于第二段代码,如果在绑定之后向#items添加更多的锚,则不需要添加新的事件处理程序。父元素#items已经包含了它们。

#1


8  

Unless you are dealing with some huge number of elements, it probably does not matter either way. The question is when do you need to be more efficient: at bind time or at trigger time?

除非你要处理大量的元素,否则这两种方法都没有关系。问题是,什么时候需要更高效:在绑定时还是在触发时?

Disclaimer: I don't claim that any of these tests are perfect. Also, I only tested in Chrome.

免责声明:我不认为这些测试是完美的。另外,我只测试了Chrome。

Binding time

I didn't know the answer offhand, so I decided to just try and test everything out. First, I assumed that using delegation would be a lot faster for binding (it only has to bind once as opposed to X number of times). This appears to be correct.

我当时不知道答案,所以我决定试着把所有的东西都试一试。首先,我假设使用委托进行绑定要快得多(只需绑定一次,而不必绑定X次)。这似乎是正确的。

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

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

Do not delegate: 100% slower

不要委托:100%慢

Trigger time

Next, I figured that not using delegation may actually be faster for triggering the events because no DOM movement is needed to check event triggering. For whatever reason, I was incorrect about that:

接下来,我认为不使用委托可能会更快地触发事件,因为不需要通过DOM移动来检查事件触发。无论出于什么原因,我对此的看法是错误的:

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

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

Do not delegate: 60% slower

不委派:60%慢?

(The initial .trigger is done just in case jQuery caches delegated events, which I believe it does. This would impact the test).

(最初的.trigger是在jQuery缓存委托事件时执行的,我认为它是这样做的。这将影响测试。

Triggering only one item

Then, I figured that not using delegation would be faster for triggering the event on one specific item. This too was wrong:

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

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

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

Do not delegate: 80% slower

不委派:慢80%

This is so even if it's not the last sibling, but one of the earlier siblings:

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

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

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

Deep Nesting

Finally, I figured that a lot of the work done by delegation has to be DOM tree parsing. That means that using delegation in a deeply nested DOM and binding to a very old ancestor and triggering takes longer than binding to and triggering on the deeply nested item itself.

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

This finally turned out to be correct:

这最终被证明是正确的:

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

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

Delegate: 90% slower

代表:慢90%

Conclusion

I can't draw any monumental conclusions here, but if you have a ton of DOM to work with, especially if it's deeply nested, you might take a look at using delegation for binding rather than binding directly.

这里我不能得出任何不朽的结论,但是如果您需要处理大量的DOM,特别是如果它是嵌套的,那么您可以考虑使用委托进行绑定,而不是直接绑定。

If anything, these examples have taught me (well, reinforced anyway) that you should try to keep the delegating element as close to the descendants that will trigger the event as possible.

如果有什么不同的话,这些例子告诉我(好吧,不管怎样,加强了),您应该尽量让委托元素与触发事件的子元素保持尽可能近的距离。

#2


3  

That's the matter of optimization. Let me explain:

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

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

With the above code, each and every anchor have own event handler. It's waste of memory because just a single handler can do same action.

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

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

Also with the second code, if you append more anchors to #items after binding, you don't need to add new event handler. The parent element, #items, cover them already.

对于第二段代码,如果在绑定之后向#items添加更多的锚,则不需要添加新的事件处理程序。父元素#items已经包含了它们。