Hacker News new | past | comments | ask | show | jobs | submit login
Differences Between jQuery .bind() vs .live() vs .delegate() vs .on() (elijahmanor.com)
325 points by elijahmanor on Feb 6, 2012 | hide | past | favorite | 60 comments



What I really like about the old style bind/live/delegate is that it's so grep-able. The new on()-based API makes it much harder to search through a codebase.

In addition, when you see something like:

    $('.table a').click(function() { ... } )
it immediately looks wrong, because there are probably multiple links in the table. Wrong code that looks wrong is great, because you can then refactor it as you come across it. But now you have to check if a second selector argument is passed to "on", to see if unnecessary event handlers are created.


This is also my biggest grip with the new .on(). I can't quickly look through code anymore since .on() can take on different meanings based on the arguments passed. When jQuery 1.7 was released I commented on this on the release notes page, I wasn't well received. It's refreshing to know that others feel the same way...

http://blog.jquery.com/2011/11/03/jquery-1-7-released/#comme...


You should take a look into event delegation with bubbling, event listeners should be minimal.

http://javascript.info/tutorial/bubbling-and-capturing

http://javascript.info/tutorial/event-delegation


The more I use jQuery, the more of a mess I see that it is. Don't get me wrong, I'd rather use it than rolling my own cross browser solution, but it is not the library that Id choose first. I simply do not like the api choices, the lib works well, the api, as seen in this article, isn't too pretty.


Backward compatibility.

Millions (if not hundred of millions) of websites rely on jQuery, switching to a newer version that breaks old code will wreak havoc and make these sites unusable.

But this shouldn't stop jQuery from improving. If you have read the article from the beginning, you'll see how the jQuery team was improving the binding functionality. It has a cost, certainly. Maybe there should be a jQuery version with no legacy code.


> Maybe there should be a jQuery version with no legacy code.

They're deprecating stuff, so it's just a matter of time. I think that's the sensible way to do things.

http://blog.jquery.com/2011/11/08/building-a-slimmer-jquery/

They're also taking steps to be able and use Google Closure Compiler's advanced optimizations, which would let you build jQuery against your code and trim out everything that's not used. Pretty handy.


> They're also taking steps to be able and use Google Closure Compiler's advanced optimizations...

That is awesome, thanks for pointing it out!


The overall api is strange. The each loops are backwards from the spec (key, value) instead of (value, key) and there are instances where it is key, value in jquery, there are instances where method names just don't make sense (I'd expect something like size to be dimensions etc), getters and setters as the same method, way too much argument overloading, inconsistent approach (selector.action, but wrap is the opposite of how the rest of the lib works). There is no kind of inheritance for their plugin architecture.

These are just things off the top of my head. I feel like jQuery is the same as PHP when it comes to api, and I make a living doing PHP.


jQuery.map() jQuery.each() having their arguments has caused me more than a few WAT moments.

One way I solve the issue around overloaded apis is by not using them. I just pretend .click() and friends just don't exist.


Yep, the best advice for a newcomer is to just use `.on()` and familiarise yourself with that API. You can ignore the other event handler methods because they're all just shortcuts or legacy methods.


I like MooTools. When they added event delegation to their library, they simply modified the existing addEvent method to parse the event name instead of adding new method after new method -- seems like a more thought out approach.

    $(selector').addEvent('click:relay(selector)', fn)


Exactly. It would simplify the documentation to simply deprecate everything but .on() but would that justify breaking all the existing code out there? Not to me. The old APIs need to stay around so that code continues to work.


Even if they excised the old methods from the code, hopefully no one is linking to jQuery trunk or something as their primary library. The old versions would still be around. Just some simple work might have to be done to update a web app to using the latest versions of jQuery.


They could deprecate the old methods and still keep them around as long as makes sense. There's no rule that deprecated methods have to be gotten rid of during the next major revision or anything.


A 2.0 release would be a reasonable point to potentially break legacy code.


Yet it breaks hilariously when you try to move from 1.3.2 to 1.4.4. I still have ONE script for which I have to deal with jquery-1.3.2.


I don't use JQuery anymore at all. I just use element.addEventListener with a polyfill for attachEvent if I need to hit old IE.


Poly-fill is the future.

Someone's working on a DOM polyfill at the moment, it's unstable beta but looks promising: https://github.com/Raynos/DOM-shim


I've often thought that frameworks should be built on top of standardized native apis, poly-filled when necessary. I imagine a time when browser specific hacks will be outside of the frameworks and "pushed down" to something lower level; ultimately shared across several frameworks rather than siloed off like it is now.


> ...but it is not the library that Id choose first.

Which library/libraries would you choose first, over jQuery?


For a complete one-off, plain JavaScript and DOM. For a small, simple project, MooTools. For a large project, Closure Tools. jQuery's not a good choice for anything I work on, and its "God Object" API makes for repugnant code.


I would use Ender and pull together various micro-libraries/modules.

http://ender.no.de


That is very interesting. It looks like they even have a "starter pack" that approximates much of what jQuery does: http://ender.no.de/#jeesh

Thanks.


I winder how it well it works with SVG?


MooTools. Dojo. The herd has been thinned a bit over the last few years.


> the more of a mess I see that it is.

I started a joke project to mock the total mess that jQuery has become, http://cowbelljs.com/ . The performance hit from using jQuery is awful these days, it's become a monolithic framework aimed towards support for a hodge-podge of things rather than using best practices.

A simple line of code such as this might be readable:

$(".foo input[type=checkbox]:checked").live(function(e){fizzbuzz(e)})

But, the costs of that? You've just killed performance, your page is probably going to have laggy response and all kinds of event listener issues crop up as you keep working, leading to you using .die, .stopeventpropegation, .stopeventbubbeling, and return false all over the place in a futile attempt to manage your events.

jQuery does a great job of letting you write less code, it also does a good job of abstracting away tasks and making things look like "magic", but it also really makes it easy to shoot yourself in the foot, with a tommy gun.

jQuery creates a lot of undesirable effects, as far as I'm concerned:

- People don't understand what their code does.

- jQuery API is a mess, and version upgrades are hard

- Best practices for a given task are not focused on, rather, "every practice" is accepted, and whatever blog post the JS novice read at the time becomes the method they write their code with (as a result, we almost never see .delegate() in use)

- The library is huge. Yes, they brag about it being only 31kb minified, but that's huge!

- jQuery code is slow.

- Nobody understands how the DOM API works any more, and because sizzle makes it easy to select complex things the authors don't even bother writing semantic HTML, so we start to see <td id="Row2Cell2"> kind of things.

- We have landed in a mess where ambitious people tightly couple their projects with an unstable API and practices that create sluggish pages.

Sure, you can use jQuery correctly, but I'd rather use a micro-framework that complements JavaScript rather than attempt to replace it with tightly-coupled abstraction layers and memory hogging through event listeners and timers all over the place. The culture around it makes me really sad.


Most of your argument boils down to "jQuery makes it easy for shit developers to write shit code, therefore you shouldn't use it". No response necessary.

> jQuery code is slow

Compared to what? What parts are slow? Keep in mind it needs to support legacy browsers like IE6 before you answer those questions.


Your post reads as if there's an undertone where you're really defensive of the library. If that's the case, there's no point discussing this further, however, lets go ahead anyway.

> Most of your argument boils down to "jQuery makes it easy for shit developers to write shit code, therefore you shouldn't use it".

Shit developers will write shit code regardless of a library, just as good developers will write good code. The problem is that jQuery provides an abstraction to what's actually happening, and how the DOM treats events in the browser. The present status-quo of jQuery code boils down to abuse of innerHTML="foo", and binding events onto individual elements rather than bubbling up to a parent listener.

As I said, the culture around jQuery propagates the web with sub-standard code simply because it attracts cut+paste+tweak developers who don't really understand jQuery, never-mind what's going on behind the curtain, or how to use events in such a way that can lead to long-term maintainability. It discourages best practices because it's really good at hiding reality from developers.

Even if you're a good developer, why should you use jQuery? You aren't necessarily getting anything more done than usual if you know what you're doing and using a micro-framework under 10kb, or expand your framework with one of the modular fameworks that let you do so. Don't like Sizzle selector engine? Use something else.

> Compared to what? What parts are slow? Keep in mind it needs to support legacy browsers like IE6 before you answer those questions.

Compared to plain old JavaScript. Almost all of it is slower, modifying the DOM, binding events, AJAX has been known to expose memory leaks (an on-going problem in other places as well), jsperf is full of people who set up test cases to see the difference between jQuery and vanilla JS: http://jsperf.com/browse

Two contrived examples, feel free to explore some more...

1. http://jsperf.com/queryselector-vs-getelementbyid-perf

2. http://jsperf.com/modern-js-vs-jquery-append

Legacy support should not be a unilateral feature that every browser has to fell the pain of, it goes against the grain of progressive enhancement practices. I don't really buy into the whole "we have to support IE6" any more that it's now under 1.5% everywhere that's in my market. However, legacy support can easily be provided through polyfills that append the DOM methods, and standard JS object prototypes, sometimes these are called shims as well, it supplements a broken legacy browser-native API with something that matches modern implementations, or in some cases, normalizes spec implementation discrepancies. This means I don't have to check for activeX object every time I goto make an AJAX request, or other costly things.


> http://jsperf.com/modern-js-vs-jquery-append

This is a trap that a lot of people fall into when benchmarking with jsperf. It is perfectly valid to say that the bare DOM functions are TEN times faster than jQuery at this particular task. But even the "slow" jQuery case runs more than 16,000 times in a second on Chrome. That ain't slow; you are unlikely to be injecting more than a dozen or so boxes a second so this isn't going to be your bottleneck.

These kind of benchmarks don't represent reality when you scale to an app where the inability to inject more than 16,000 boxes into a page per second might even conceivably be a bottleneck. It would be much more common, for example, to be building HTML templates via Mustache and injecting them all at once. Show me the comparison of doing that whole thing with DOM functions. :)

It is always better to start with some real code that is not performing well and find its bottlenecks. With that in mind I agree that using .live() with complex selectors or high-frequency events like mousemove is bad design. Preventing that sort of unknowing abuse is exactly why we deprecated .live() in 1.7. But I disagree with the generality that "jQuery is slow" simply because it doesn't compare well on some isolated jsperf tests, or because it provides powerful abstractions that can be abused.


Actually this test is illustrating a performance problem with the wrong thing, which is what makes it so dangerous. jQuery append is fine. It's actually the $('<div id=box></div>') vs document.createElement('div') that is the real performance killer. Which can be easily resolved by doing $(document.createElement('div'))


I entirely agree with you, I'm not about to say jsperf is able to give an accurate representation of the big picture and show your bottlenecks, however, it does demonstrate that jQuery code is actually much slower. The impact is worse when the most culturally-popular methods in JavaScript: replacing innerHTML inside for-loops, and attaching events directly to many elements.

That being said, I have run into situations where I absolutely do need performance. I've tried to load 10k records into the popular http://www.datatables.net/ plugin (I have a legitimate reason, I swear), and it tends to crash my browser simply because the author uses a lot of these per-element-bindings and innerHTML calls, but I was about to use jqGrid http://www.trirand.com/jqgridwiki/doku.php which managed to write the jQuery code in a way that avoids those bottlenecks and is able to deal with 10k records without crashing. So yes, you can use jQuery and write better performance than other cases out there, but that's not what I'm trying to get at.

I'm saying jQuery encourages a lot of bad things that competent programmers can avoid without using this specific library for everything, and novice programmers can gain a better understanding of the browser through not using "hocus pocus" to make sites.


I see jQuery misused every day, I'm pretty sure I was one of those terrible people a couple years ago. Since then I hardly use jQuery anymore except for delegate() and that's only because I haven't explored other libraries to replace it.

jQuery, if used responsibly, is still a good library.

Unfortunately, you are correct that the culture around it stinks. jQuery is the tool of choice for bad developers to write bad code.


Jquip is trying to make jquery less messy by splitting into separate modules.


But it failed to use a proper module format (e.g. CommonJS / AMD)


I've been using Prototype for years and am now using jQuery more, and I have to agree. The knock against Prototype was that it modifies built-in classes, but I seriously doubt how much that actually matters, and as a programming library it makes much more sense to work with, I think. jQuery doesn't even offer very useful things like list comprehensions! You have to use underscore to get those.


Actually, splitting out logical code from DOM manipulation code makes plenty of sense. Just because I'm using one does not mean I want the other and both stand on their own fairly well. This is even more important now that JavaScript is popular on the server--I can use Underscore there as well.


There is a grep method that does some stuff:

http://api.jquery.com/jQuery.grep/


> The method attaches the same event handler to every matched element in the selection.

Why is that a con for .bind()? This used to be considered a performance benefit compared to onclick.


I think you misread this. It does not bind the same instance of the handler to each element. Each element gets its own copy of this handler, hence the waste of memory.


What? No they don't, unless you're making the handler in a loop.

$( "div" ).click( function() {} );

Each div will have the same handler applied, it doesn't make a new one for every div.


You're confusing the callback with the actual event listener.


Compared to onclick, it's certainly a performance benefit.

However the difference here is in looping over every matched element to add the handler (bind) versus adding the handler to a single element further up the DOM tree (delegate).


I experienced this dilemma first hand. Thank you very much for explaining it clearly.


That html snippet at the top is quite strange - it's not legal to put an H3 or a P in an A.



on a slightly less relevant note. is live() pronounced as live as in live wire or live as in die/live? we had a little debate going here on our office about this and we need closure dammit!


I'm pretty sure it's live like live wire. The event is alive.


On the other hand, the opposite of live() is die(). Odd.


Here you go: http://www.mrspeaker.net/2009/11/12/how-to-pronounce-live/

A definitive answer to this very important question.


Like live wire


I see "it's" used as the possessive pronoun so often and so deliberately by educated authors that the descriptive linguist in me is starting to think "its" has been deprecated. Still, the prescriptive linguist in me is repulsed.


Don't forget to check out livequery.

http://docs.jquery.com/Plugins/livequery

"Live Query utilizes the power of jQuery selectors by binding events or firing callbacks for matched elements auto-magically, even after the page has been loaded and the DOM updated."

Oh so awesome.


Why? That plugin was created before jQuery had .live() (which has since been made useless by the better delegate/on).

The only reason you should use this plugin is if you're stuck with jQuery <1.3.


Perhaps I'm mistaken about this, especially since this article was my first time hearing about delegate, but I believe that live and delegate are only able to be used for existing DOM events like "click", etc., whereas livequery calls a function on occurrences like elements appearing in the DOM, for which there is no built-in way to watch with jQuery.

I usually use it to watch when elements appear and then bind handlers to them inside the callback. Kinda does away with the need for live.


That's exactly what live/delegate/on does. You can bind events to "future" DOM elements.

You don't need to watch for the elements though. You just delegate the event to an element/selector higher in the DOM tree and use event propagation/bubbling.

I suggest you read up on event delegation.


But can you detect when DOM elements are created? (Which is different than adding a click event to new DOM element.)

I was looking into this issue myself recently and ultimately (through advice on Stackoverflow) decided to just ignore jQuery and to use DOM mutation events. I'm still curious if there is a way to do this using jQuery, though.

While working on this I briefly considered livequery due to this StackOverflow post (http://stackoverflow.com/questions/4818020/livequery-perform...), but soon realized that this only intercepts DOM changes made via jQuery, and won't work with code in the wild (which is what I need since it is for a Chrome extension.)


You can use the DOMNodeInserted event. Something like this:

document.addEventListener("DOMNodeInserted", function(event) { console.log($(event.target).parent()); });

That will log the element that gets inserted into the DOM.


That's roughly what I'm doing now (i.e. DOM mutation events). It just isn't using jQuery.


Is that a problem? You can use jQuery to wrap the event target like my example did. Or just do $(document).bind('DOMNOdeInserted', function () {}); Is that using jQuery enough? I suppose if you knew you were only using jQuery and wanted to modify the source, you could somehow hook into every function that modifies the DOM and go from there (which is what you just described with livequery).

Not really sure why your requirement is it needs to "use" jQuery though.


Not really; my code is working fine as is. I think the "problems" were 1) I was curious if there was a way to do it via jQuery instead of DOM mutation methods (looks like no) and 2) the documentation for these jQuery methods doesn't specifically mention that this case isn't covered and that the developer should look at DOM events, although that is just perhaps assumed to be default behavior when working with jQuery.

I'm writing to the people who maintain the jQuery documentation now...




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: