5

I read the following:

"if users can interact with a lot of elements on a page, adding event listeners to each element can use a lot of memory and slow down performance...

...because events affecting containing elements you can place event handlers on a containing element and use the event target property to find out which of its children the event occured on"

So, what are the downsides to just doing one click event on the body and then delegating the correct function?

I have an example here: http://jsfiddle.net/jkg0h99d/3/

Code backup for deadlink:

HTML:

<div id="test" class="box">gfdgsfdg </div>
<div id="test2" class="box">gfdsgfdsg</div>
<div id="test3" class="box">fdsgfdsgg</div>
<ul id="test4" class="box">
    <li id="test5" class="box">fsgfdsg</li>
    <li id="test6" class="box">gfdsgfds</li>
    <li id="test7" class="box">gfdsgfds</li>
    <li id="test8" class="box">gfdsgfds</li>
</ul>

JS:

var body = document.body;

if (body.addEventListener) {
    body.addEventListener('click', function (e) {
        delegate(e, "click");
    }, false);
} else {
    body.attachEvent('onclick', function (e) {
        delegate(e, "click");
    }, false);
}


function delegate(e) {
    var sourceNode = e.target || e.srcElement;
    var id = sourceNode.id;
    switch (id) {
        case ("test"):
            // do some func
            break;
        case ("test2"):
            // do some func
            break;
        case ("test3"):
            // do some func
            break;
        case ("test4"):
            // do some func
            break;
        default:
            // do nothing
            break;

    }
}

Interesting point: It will raise an event every time a user clicks. But, is that really going to be a problem? All it does is check through a switch (or could be if checks)

The point of this is mere interest, however a user has asked about the point optimisation. I am thinking this could very quickly be optimised further but I will keep the discussion on topic.

Fred Johnson
  • 2,539
  • 3
  • 26
  • 52
  • 3
    If you put all of it on the body then any click you make on the page will need to go through it. The performance hit is more noticeable on mobile devices – Huangism Jan 28 '15 at 20:48
  • 2
    With that number of elements, I wouldn't even worry about it. Unless you have profiled your code and found this to be a bottleneck, it's premature optimization. If you have several elements that all need to do the *same* (or very nearly the same) thing when clicked, it makes sense to attach a handler at a higher level. Otherwise, I think that `switch` statement is going to be a bit of a nightmare. – Matt Burland Jan 28 '15 at 20:50
  • Yes, it was a demonstration. And I think Huangism raises a very good point, thank you – Fred Johnson Jan 28 '15 at 20:51
  • 1
    Exactly what @Huangism said, so usually you should try and find some “middle ground”. You might have a larger number of elements on a page that need a (common) click handler, but if those are grouped by a container element then you could place the handler on that element, instead of going “all the way up” to body … especially if there is lots of other elements that don’t need their clicks handled at all (or by a different handler function). – CBroe Jan 28 '15 at 20:51
  • @user2330270: if you've profiled it, then what are you asking? Go with which ever one works better. – Matt Burland Jan 28 '15 at 20:51
  • To answer the question, the downside is of course that attaching all click events to the body, or more appropriately to the document, will mean every single click has to go through a filter to see if the event target **and** any of it's parent elements to account for bubbling, match the element you're looking for, which most of the time is a lot less efficient than having a few more event handlers attached. There is probably a limit, somewhere around thousands of elements with seperate handlers, where delegation makes sense. – adeneo Jan 28 '15 at 20:54
  • But it wont bubble further than to HTML and doc. – Fred Johnson Jan 28 '15 at 20:57
  • @adeneo it will only do a quick switch case, so surely unless you use a rediculous amount of click events it'll be fine? And the code is halved – Fred Johnson Jan 28 '15 at 21:01
  • If that's all you're worried about, there's easier ways to do that, like this -> **http://jsfiddle.net/jkg0h99d/5/** – adeneo Jan 28 '15 at 21:09
  • @adeneo But that wont work if you want different functions on different events. My idea is quite simply "why not" and so far I can only see a downside if there's a considerable amount of elements with click bindings – Fred Johnson Jan 28 '15 at 21:15
  • However you raise an interesting option – Fred Johnson Jan 28 '15 at 21:16
  • http://jsfiddle.net/z1hx8yn1/ – Fred Johnson Jan 28 '15 at 21:19
  • Why do you keep adding `attachEvent`, the rest of the world has stopped supporting IE8. – adeneo Jan 28 '15 at 21:21
  • Because I'm mad, havent you noticed? – Fred Johnson Jan 28 '15 at 21:28

1 Answers1

0

As with most things of this nature, the answer is "it depends" and that you need to pick a middle ground. In general, the advice is to place events at least relatively close to their source in the DOM tree to avoid excessive bubbling, and to avoid placing events on the body unless it's necessary.

As an example, you could place a handler on your ul to handle event delegation for your lis:

document.getElementById('test4').addEventListener('click', function (e) {
    // handle event for li
});

This gives you the best of both worlds because you:

  • Have one event bound to your DOM to handle li clicks instead of a separate copy for every li
  • Don't have to reattach events if the set of lis is dynamically modified
  • Have minimal bubbling (just one level)
  • Don't have to multiplex the logic in a big ugly switch statement

So I think that's a worthwhile principle to keep in mind.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • 1. The event was bound to the body so it will only bubble to HTML level. If you did it on each element, it will still bubble upwards so more care is required for beginners 2. You could optimise the switch to only account for the ul, it was a quick demonstration 3. see #1 4. Ok, maaaaybe you got me ;) but I will argue my point, is a switch more or less clear than a load of event code? 5. Please see http://jsfiddle.net/z1hx8yn1/ for specifying the nodes to attach events via class selection 6. Thank you for your reply, it is appreciated – Fred Johnson Jan 28 '15 at 21:27
  • @user2330270 My first point had nothing to do with bubbling. With regards to bubbling, your understanding is bubbling is backwards. If someone clicks on an element deep within the DOM, that event has to travel up from parent to parent until it gets handled. _That_ is where the performance concern is with bubbling. – JLRishe Jan 28 '15 at 21:33
  • @user2330270 You don't have to believe me about the bubbling concerns. See what the [jQuery documentation](http://api.jquery.com/on/) says about event bubbling performance: _"For best performance, attach delegated events at a document location as close as possible to the target elements. Avoid excessive use of document or document.body for delegated events on large documents."_ The fact of the matter is, almost nobody uses a single event handler to handle all the events on a page, so that should be a pretty good hint that it may not be the best way to go. – JLRishe Jan 28 '15 at 21:34
  • Ah interesting. This seems to contradict my book, which is what lead to this. It says if you have events bound on say a header and child elements, then when you click a child element, it will fire any click events bound to any/all parent nodes. From what you are saying, it gets absorbed? – Fred Johnson Jan 28 '15 at 21:36
  • @user2330270 An event handler on the child would have the ability to stop the propagation (with `e.stopPropagation()`) and prevent the event from bubbling up any further. – JLRishe Jan 28 '15 at 21:37
  • What confuses me is this. If I click an element deep within the DOM, are you saying it doesn't just go "that was a click on the body", it goes "that clicked div100, no event handler, clicked div99, no event handler, clicked div98.... etc until it reaches body, and then handles the event? – Fred Johnson Jan 28 '15 at 21:46
  • @user2330270: But before you might now think that `stopPropagation` is “the panacea of event handling” and it should be stuffed into each and every event handler ”just in case”, you should go read http://css-tricks.com/dangers-stopping-event-propagation/ – CBroe Jan 28 '15 at 22:04
  • @user2330270: Yes, now you have understood what event bubbling means. _From_ the element that the click was originally made on, the event travels _all the way up_, to the parent, to the parent’s parent, to the parent’s parent’s parent, and so on, until it eventually reaches the root element (which is `html`). And for each element encountered on the way, the browser has to check if there are any event handlers attached at that particular level. – CBroe Jan 28 '15 at 22:06
  • @user2330270: Check out http://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing as well, that should provide some more insights. – CBroe Jan 28 '15 at 22:08