Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there advantages or disadvantages to binding on a parent element versus the element directly?

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:

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:

$('#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.

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.

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

like image 226
naivedeveloper Avatar asked Jan 31 '13 04:01

naivedeveloper


2 Answers

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.

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.

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

Do not delegate: 100% slower

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:

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

Do not delegate: 60% slower

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

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

Do not delegate: 80% slower

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

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.

This finally turned out to be correct:

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

Delegate: 90% slower

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.

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.

like image 189
Explosion Pills Avatar answered Oct 22 '22 08:10

Explosion Pills


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.

like image 43
SangYeob Bono Yu Avatar answered Oct 22 '22 08:10

SangYeob Bono Yu