How many elements does it take for event delegation to become worthwhile?
Asked Answered
P

1

11

Reading another Stack Overflow question about jQuery performance, I started thinking about the point when it becomes worth using event delegation rather than binding to elements individually. I was thinking mainly about jQuery, but I suppose it is probably applicable for Javascript in general.

Event delegation has two main purposes:

  1. allowing handlers to work on elements that have not yet been created/inserted into the DOM.
  2. binding one function to a common ancestor element rather than to multiple sibling elements

My question is about the second of these. The general answer will probably be "it depends on the exact situation", but I wonder if there is a rule of thumb or a way of benchmarking in order to test this.

So, the question is: how many elements do you need before the performance benefits of event delegation outweigh the performance costs?

Peaked answered 15/10, 2010 at 22:32 Comment(12)
I don't know about the performance costs of event delegation... What are they? Events bubble up anyway, and the event target is is stored in the corresponding property of the event object at all times.Lordling
@Sime The main one I'd thought of was that every time an event is fired, the selector in the delegate call has to be run to check if it matches the event target. There may be others...Peaked
Consider that when you use delegation, you're effectively spreading out the cost of binding handlers over the page lifetime. When you bind by finding elements first, you add more work at page load time, when users are most sensitive to delays.Deeprooted
Can you post code? I think you have it backwards.Unmeet
Also it's not just about how many elements are involved - it's also how the events will be generated. For events that cause the page to be reloaded, it probably doesn't matter. For a game, where an event represents input from a real-time controller, it might make a difference.Deeprooted
@Peaked - it's not exactly like that, bubbling carried out without testing objects against selectors. only live handlers are differentDott
@Peaked The delegate() method of jQuery is one thing, and event delegation as I know it is another thing. From what I understand, event delegation is when you attach one event handler to a common ancestor element instead of attaching a handler for each element (like, attaching it to a table instead of each table cell). I don't think that this process has performance costs. The jQuery delegate() method, however, may have...Lordling
@Dott $('#el').delegate('a[href^=http://www.google.com]', 'click', func) The selector a[href^=http://www.google.com] will be run against the target of every click event that reaches #el, I believe.Peaked
@Sime Maybe this question is too general and non-specific... I would have thought that you would almost always need to check the event target was the one you wanted when using delegation.Peaked
@Peaked You don't with jQuery's delegation methods, because the selector you provide already achieves that. So jQuery itself checks but you don't have to in your own code. It's expensive, but remember checking a single element against a selector is much much cheaper than applying the selector to an entire page.Deeprooted
@Peaked sorry misread you post, you are right, it willDott
It's not just a question of how many elements, but of how hard they are to select. If they all have id's, you can bind to more of them individually for the same cost as binding to significantly fewer elements which you can only select, for example, in terms of nesting ("ul ul li") or of an attribute's value.Sectarianize
P
3

Assuming this HTML structure:

<ul id="navUL">
    <li><a href="one.html">One</a></li>
    <li><a href="two.html">Two</a></li>
    <li><a href="three.html">Three</a></li>
</ul>

Just to clear things up (for me) .... According to jQuery docs ( http://api.jquery.com/delegate/ ), this:

$("#navUL").delegate("a", "click", function(){
    // anchor clicked
});  

... is equivalent to this:

$("#navUL").each(function(){
    $("a", this).live("click", function(){
        // anchor clicked
    });
}); 

However, event delegation (as I know it) is this:

$("#navUL").click(function(e) {
    if (e.target.nodeName !== "A") { return false; }
    // anchor clicked
    // anchor is referenced by e.target
});  

So you catch the click event on the UL element, and then figure out which anchor was actually clicked via the event.target property.

I don't know about the delegate() method, but this last technique should always be faster than attaching event handlers to each anchor in the #navUL element, like so:

$("#navUL a").click(function() {
    // anchor clicked
    // anchor is referenced by the this value
});
Procora answered 15/10, 2010 at 23:9 Comment(3)
Don't you need an e.stopPropagation(); in your delegation as you know it example?Brewery
Hm, why? The user clicks somewhere inside the #navUL element. The click event propagates to the #navUL element (since there are no click handlers attached to A or LI elements). Inside the #navUL click handler, I check if an anchor was clicked. If not, I just kill the event (via return false;). If yes, I do what I intended (with the anchor). I may want to prevent the default behavior of the anchor, but I don't see why I would want to prevent the click event from bubbling up the DOM tree (I don't have any click handlers set on ancestor elements, anyway).Lordling
OK, I can go with the "always" answer. It fits with what I do anyway. Thanks.Peaked

© 2022 - 2024 — McMap. All rights reserved.