2

The jQuery API documentation states that we should use the newer on() function instead of the older (sometimes deprecated) ways of attaching an even handler to elements.

From my understanding, the on() requires to be bound to an element that "currently exists" in the page (DOM). In these days of building web sites where pages are mostly dynamically loaded (via Ajax) and injected, this pretty much forces us to bind it to the document element.

I have mostly used the live() method to bind to "future elements". This worked well for me, but I can't simply replace my live() for the newer on() because my elements don't yet exist and if I do, nothing works.

I could simply use $(document).on() instead but I'm scared of a huge overhead that it seems to impose on event delivery. At least from what I understand from their documentation.

Can anyone comment on the potential penalty the on() function may bring in my particular case. And possibly, if anyone can comment on what the rational is for jQuery to constantly deprecate their event binding API's (which is not backwards compatible in this case)?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jeach
  • 8,656
  • 7
  • 45
  • 58
  • Have you heard of http://jsperf.com/ ? – Daedalus Mar 05 '14 at 02:29
  • tldr; But what you are asking is visible from Jspref and read more about `.on` will tell you what all stuff it does inside. http://stackoverflow.com/questions/11115864/whats-wrong-with-the-jquery-live-method/11115926#11115926 **or** **JSPERF Demo** http://jsperf.com/bind-vs-live-vs-delegate-vs-on/5 Might help bruv `:)` – Tats_innit Mar 05 '14 at 02:30
  • 1
    `$(selector).live(event, fn)` is the same as `$(document).on(event, selector, fn)` – elclanrs Mar 05 '14 at 02:30
  • 1
    @Tats_innit Thanks for the other SO question... never got a hit with Google and when I typed out my question, it never listed it in its list... thanks! – Jeach Mar 05 '14 at 02:33
  • @Jeach glad it helped! Hope you sorted now `:)` – Tats_innit Mar 05 '14 at 02:33
  • @elclanrs What do you mean by "the same"? Document is guaranteed to always exist but selector is not. When I use to bind my event handlers, I would do it using live() on an element that did not yet exist. Doing the same with on() will not work. – Jeach Mar 05 '14 at 02:34
  • Which ones won't work? Can you post an example? – elclanrs Mar 05 '14 at 02:37
  • 1
    @Jeach Read [Direct and delegated events](https://api.jquery.com/on/#direct-and-delegated-events) – quietmint Mar 05 '14 at 02:44
  • @Tats_innit The problem with the JSPerf demo (correct me if I'm wrong) is that it does not have a deep nested tree of DOM elements. In my case, I'm binding click events to divs that are probably 15 or 20 levels deep from the document. Would the JSPerf benchmark be different if I was to create thousands of elements that go 20 levels deep hierarchy of elements? I'm not sure, I could be wrong here? – Jeach Mar 05 '14 at 02:49
  • Regarding deeply nested elements, you'd have the same issue using `.live()` as you would binding `.on()` to the `document`. – cookie monster Mar 05 '14 at 02:50
  • @cookiemonster Thanks for that info! I thought that live basically attached the event to the selector element when such element got attached to the DOM so that when an even happened, it would only propagate the event to the actual selector element, which in my case was only two div's up. The way I understand it is that if my on() selector is the document then the event gets propagated all the way to the document ALL the time. I'll have to investigate this further. – Jeach Mar 05 '14 at 02:55
  • @Jeach: Yeah, `.live()` bound all of its handlers on the `document`. The selector was only used for matching the elements between the `e.target` and the `document`. Many people didn't understand what `.live()` was doing, so I'm sure that's why they got rid of it. – cookie monster Mar 05 '14 at 03:00
  • 1
    @cookiemonster "Many people didn't understand what .live() was doing"... and I'm guilty of this as well. I now understand why I was completely misled by the live() function. The on() makes a lot of sense to me now! – Jeach Mar 05 '14 at 03:46
  • @user113215 Great reference, it was a useful read! Am I understanding it correctly that all events bubble up to the document regardless? If so, then regardless if you have a handler directly on the element or attached to the document, the browser will still spend time bubbling. Its just that your handler will be executed a little sooner. Is this a correct assumption? – Jeach Mar 05 '14 at 04:13
  • 1
    @Jeach Yes, events will bubble up the DOM unless some handler in the chain calls `event.stopPropagation()` or `event.stopImmediatePropagation()`. The advantage of delegated events is that 1) the target need not exist at the time you bind the handler and 2) one handler works for multiple targets. – quietmint Mar 05 '14 at 16:31

3 Answers3

3

Well, they're all basically the same

This is the source of bind<source>

function (types, data, fn) {
    return this.on(types, null, data, fn);
}

this is the source of live <source>

function (types, data, fn) {
    jQuery(this.context).on(types, this.selector, data, fn);
    return this;
}

and this is the source of delegate <source>

function (selector, types, data, fn) {
    return this.live(types, data, fn, selector);
}

They're all basically the same, you could probably guess the perfomance differences just by looking at them,

To sum up, all 3 of on() "predecessors" do noting but call their "successor"

As mentioned in the comments, Rochas has made a jsPerf which will show you the performance differences by running tests in your browser, two of the live test fails because of an now incompatible jQuery version, but as you can see from the source, it's the same as on anyway. jsPerf Benchmark

iConnor
  • 19,997
  • 14
  • 62
  • 97
  • They're not identical to `on`, however. `live` at least, will always have worse performance than a well targeted `on` expression. They can't be used interchangeably. – Asad Saeeduddin Mar 05 '14 at 02:55
  • Because it delegates to the document root, instead of to a more specific common ancestor, which is made possible by `on`. – Asad Saeeduddin Mar 05 '14 at 02:59
  • The `context` property nearly always points to the document, except when you pass a second argument to `$`. Also, I never said in my answer that it is identical. Please read the answer more carefully. There is a huge difference between the behavior of `$(document).on` and `$(somenodeinthedocument).on`. – Asad Saeeduddin Mar 05 '14 at 03:05
0

TL;DR: live delegates event handling for all elements matching the selector expression to the document root. This is functionally equivalent to $(document).on, so you aren't gaining or losing anything performance-wise by switching to the newer API.


Quoting your question:

From my understanding, the on() requires to be bound to an element that "currently exists" in the page (DOM). In these days of building web sites where pages are mostly dynamically loaded (via Ajax) and injected, this pretty much forces us to bind it to the document element.

You seem to be suggesting that the only thing that exists on the page at the moment you do your binding is the document, which is an unrealistic scenario. Even if your entire document is assembled using nothing but jQuery, you can still bind delegated event handlers to the elements you are inserting dynamically, right after you've inserted them.

For example, see this fiddle:

<html>
    <head>
        <script>
            var myDynamicElement = $('<div class="dyn_el">Please click this button: <button>Click!</button></div>');
            $('body').append(myDynamicElement);

            myDynamicElement.on('click', 'button', function() { alert('Works!'); });
        </script>
    </head>
    <body>
    </body>
</html>

There is no legitimate reason to use live over on, especially since the former internally behaves identically to $(document).on.

Note: While the other answer points out that live internally calls "its successor", this does not mean that they are interchangeable! live will always perform worse than an on delegation to an element lower in the document hierarchy. This is because live delegates to the document root, which means any and all events must bubble all the way up to the document before being disqualified or qualified by the selector expression used with live.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • 1
    I think every single jQuery method requires it to be bound to a existing Element – iConnor Mar 05 '14 at 02:34
  • Yo, `.live` is deprecated for a reason `:)` peeps from JQ tell me so as well! so this is not true from your post above : [Quote]There is no legitimate reason to use live over on, especially since the former internally behaves identically to $(document).on.[Unquote] – Tats_innit Mar 05 '14 at 02:36
  • @Tats_innit Yes, the fact that `live` is deprecated means that you shouldn't be using it instead of `on`. Especially since there are no arguments for using `live` instead of `on`. I don't see how this contradicts anything I said in the answer. – Asad Saeeduddin Mar 05 '14 at 02:38
  • The site I was maintaining was essentially an empty html document and everything was downloaded and injected. The way it was implemented was that the handler were bound to an element once and regardless how many times the page got flushed out and put back in (via user navigation), there was no need to unbind/rebind the handlers. This no longer works with on(). So now, by upgrading jQuery, I would need to keep doing the unbind/rebind. – Jeach Mar 05 '14 at 02:40
  • @JustDon't What does that have to do with anything? – Asad Saeeduddin Mar 05 '14 at 02:42
  • @Asad The fact that you said "the on() requires to be bound to an element that "currently exists" in the page (DOM)" Implies that the rest do not. – iConnor Mar 05 '14 at 02:48
  • 1
    @Jeach Okay, so then use `on` to bind to the lowest common ancestor that persists on the page for a significant amount of time. At **worst** this can only be as performant as `live`, never worse. – Asad Saeeduddin Mar 05 '14 at 02:48
  • @JustDon't That's a quote from the question. Blocks of text with gray background and non monospace font are blockquotes. – Asad Saeeduddin Mar 05 '14 at 02:49
  • @Asad OK, I didn't realise, why didn't you point that out, the point still stands anyway – iConnor Mar 05 '14 at 02:50
  • @JustDon't If you want to comment on the question, comment on the question. – Asad Saeeduddin Mar 05 '14 at 02:52
  • @Asad I don't want to comment on the question, the only reason I commented was because I misunderstood the source of that and thought your answer was a bit deceiving, which I was proven wrong. There is no need to escalate the conversation. – iConnor Mar 05 '14 at 02:55
0

Below is the best explanation of the difference I found. Reading it you can replace explanation for delegate() by .on() THE DIFFERENCE BETWEEN JQUERY'S .BIND(), .LIVE(), AND .DELEGATE()

Technically on() is now the actual function, delegate defers to on, and live is deprecated perf Test shows that .on() is slightly faster event delegation perf

last advantage is that there exists an .off() function (useful for turbolink/pjax sites) ....and it is less to type ;-)

Nadir
  • 695
  • 8
  • 12