jQuestion

The other day someone asked me again about what I thought about jQuery, and I’m getting tired of repeating myself for almost a year. jQuery actually is fodder for an interview question I sometimes ask:

What’s wrong with the jQuery $() function?

[Showing you the money after the jump.]

What is $?

If I take the example from this article:

$('#external_links a').click(function() {
    return confirm('You are going to visit: ' + this.href);
});

Here, $() is equivalent to the $$() function in prototype. And $(‘#…’) is the same as $() in prototype which is a “safe” way to do document.getElementById() + some stuff to object prototype inheritance to correctly work in Internet Exploder.

It is a very attractive shortcut if you don’t stop and think about its consequences. In the example given, the above code is a shortcut for the following more verbose code:

var external_links = document.getElementById('external_links');
var links = external_links.getElementsByTagName('a');
for (var i=0;i < links.length;i++) {
    var link = links.item(i);
    link.onclick = function() {
        return confirm('You are going to visit: ' + this.href);
    };
}

Looks pretty cool huh? Looks are deceiving. The more verbose code executes faster, plus, it isn’t all that realistic… your external links wouldn’t be located in some place but would instead be referenced by class name. Even faster code would look like.

for (var i in document.links) { // technically a for-do is marginally faster
    var link = document.links[i];
    if (link.class !== 'external') { continue; }
    // better and more DOM scripted to replace the below with a YAHOO.lang.augmentObject
    link.onclick = function() { return confirm('You are going to visit: ' + link.href); }
}

It’s all about the Benjamins

The first time my ex-girlfriend saw me code PHP, she asked me:

“What’s with all the money in PHP?”

It took a while to understand she was referring to the dollar signs in the language. And geek that I am, I actually explained to her what variables are.

But that’s the problem with jQuery in a nutshell. It makes a function look a lot like a variable. How is that a problem? Let’s look at this:

$('#blah').href = 'http://www.example.com/';
$('#blah').style.display= 'none';
$('#blah').style.visibility = 'hidden';

Oh, don’t tell me you’ve never seen someone do this! Programmers are lazy and I call bullshit on that. When you make something look like a variable, a programmer is going to start treating it like one.

I like to say:

The reason document.getElementById() is hard to type is because it’s slow to execute.

Oh, I’m sorry, it’s even slower to execute because this isn’t even doing a getElementById(), it’s doing a xpath search selector (getElementsBySelector()) which is even slower! And where is the optimizations for taking advantage of the built-in and infinitely faster document.images or document.links?

It gets worse from there because of DOM scripting. Not that there is anything prima facia wrong with DOM scripting, it’s just that programmers have a tendency to DOM script without considering the very real performance consequences. I spent a few days undoing the DOM scripting of hyperlinks that a developer hacked in via YAHOO.util.Dom.getElementsByClassName(). Hyperlinks!!! My God, man. They’re links, they’re supposed to be “linked.”

Show me the money

When I heard about this style syntax in prototype I was attracted to it for all of ten seconds. Abstraction costs and that should be intuitively obvious to the casual observer. In jQuery programmers are abstracted from the very real costs of their actions. This leads to sloppy and slow UI code. Almost all jQuery code I’ve seen executes slow for what it does.

jQuery is basically modelled after prototype. Is it any surprise that prototype is both heavily adopted and influenced by Ruby on Rails developers? What is it about Ruby acolytes that they wish to abstract themselves from the very parts of their systems that they know will be their bottlenecks?

Beyond that, is what I really want in a framework library—be it prototype or jQuery: a bunch of useless macros with some backward compatibility window dressing? History has shown that the most successful frameworks are ones that abstract and standardize the graphic user interface, not ones which give me a forced structures for events, ajax, iteration and the like. I am usually willing to pay for that “crap framework” cost only if it gives me real return in the form of higher order user interface widgets where the real programmatic cost-savings occur. User interface always ends up being at least half your code base, and it’s definitely the half programmers like to code the least and it’s often the half with the most bugs in it—users just don’t seem to behave like we want them to.

Stop preaching me your “framework religion” in the form of base structures and bullshit shortcuts and start giving me results in the form of fast, light, powerful user interfaces.

Until then, you’ll just be interview question fodder: another Javascript Framework developer bites the dust.

15 thoughts on “jQuestion

  1. Michael

    Right on Terry. But what do you mean about Scriptaculous? It doesn’t have much in terms of widgets. Drag-n-drop is widget-ish and there is the auto-complete text box, but everything else is FX. And you have to suck down a bunch of Prototype to use Scriptaculous, because Scriptaculous uses those useless macros (especially Prototype’s “I wish JS was Ruby” class based inheritance scheme.)

    Reply
  2. tychay Post author

    @Michael: True, compared to YUI or Dojo it’s nearly barren, but at the time they were looking at it (2005), the autocomplete and drag and drop controls were very big UI widgets that were a pain to code.

    I’m trying to imply, with the link, that in 2005 scriptaculous attracted people to prototype (and to Ruby on Rails), but things move forward, if you don’t catch up, you might as well be standing still. YUI didn’t exist in 2005. In two short years, its amassed something impressive. What will happen in the next two?

    jQuery is only one year old, but it’s really got to kick it into high gear if its to catch up. And I’m trying to point the way.

    There is some room here. YAHOO utils.js has bloated to a whopping 80kb unzipped,26k compressed. The 80kb is getting dangerously large, IMO, especially for something that is missing UI widgets (though it is easy to add them).

    Reply
  3. tychay Post author

    I accidentally deleted a comment critiquing this article (at least I think so, I was scanning and thought I hit the “approve” button). Can you please repost if I can’t recover it? (It began “Yeah, because nobody…”) :-(

    Reply
  4. Mark Armendariz

    While I don’t disagree with your stance in the article, your “lazy” example would actually look like this in jquery:

    $(‘#blah’)
    .attr(‘href’, ‘http://www.example.com/’)
    .css({display: ‘none’, visibility: ‘hidden’});

    Which only adds up to one search for #blah and potentially handles any cross-browser issues you might run into setting those attributes and changing those css properties (likely none for this particular example).

    Using such frameworks can slow things down, but on the other hand they can speed up prototyping stage by leaps and bounds – especially when dealing with multiple browsers and OS’. For the most part, the slowest calls can be replaced easily when necessary.

    [Ed: on request, corrected a typo —terry]

    Reply
  5. tychay Post author

    Mark,

    I was aware that there is functionality in the framework to do what you mentioned (that stuff is modeled after the way most animate classes work), and in general I approve of the philosophy behind jQuery and prototype that seems to acknowledge the prototype-based design in Javascript moreso than some of the other frameworks. However, I’ve seen far more of the the code I gave than yours. Also, your code still executes slower than a more direct approach (temporary variables). Whether or not it is more readable is a matter of debate. (I always felt that the “have a method return an object so I can do another method on it” idea that I see in this and many other frameworks—including PHP ones—a little too clever for it’s own good. pretty soon people are resorting to weird formatting in order to make it readable.)

    My general point is that while the programmatic focus is more on these framework religions, the practical focus is on powerful gui widgets. If you want to convince a real pragmatic programmer to use a framework, it’s got to give you a powerful graphical user interface, not just enable you to build it. Scriptaculous did so in it’s time period, but the world has moved forward at a rapid place to the point where Mike asks, honestly, what I was talking about.

    Asked differently, what do you think what attracts a Macintosh programmer to using Cocoa: the Foundation Kit or Application Kit?

    Most programmers I know could do without Objective C, but they eat it, not because of Foundation, but because they need those to use Application Kit and Interface Builder.

    Reply
  6. Braden

    Thanks for letting me know that you didn’t just reject it as dumb.

    “Yeah, because nobody,” I said, “would want to use a tool that made it easy for incompetent developers to fake it. PHP, say?”

    As Mark pointed out, developers who think about what they’re doing will cache query results, whether by chaining or temporary variables. And if you’re reasonable, jQuery gives you a lot of elegance without noticeable delay on the client. This, for example, is quite readable and performant, I think:

    $(function() {
    $(‘form.commentdelete’).submit(function () {
    if (!confirm(‘Are you sure you want to delete this comment?’)) {return false;}
    markFormActive(this);
    var self = this;
    $(this).ajaxSubmit({
    success: function(data, stat) {
    $(self).parents(‘.comment’).fadeRemove();
    clearAjaxMsg();
    unmarkFormActive(self);
    },
    error: function(xhr, stat, e) {
    clearAjaxMsg();
    displayAjaxErr(‘Comment deletion failed.’, stat, xhr);
    unmarkFormActive(self);
    }
    });
    });

    I’d bet that in most cases, jQuery’s automatic binding to onDOMReady rather than onload alone adds more perceived responsiveness than using document.links/forms/images would.

    Also, jQuery UI’s calendar and autocomplete plugins, as examples of GUI widgets, are quite polished and degrade beautifully. For more complicated widgets, jQuery works well with Ext.

    Reply
  7. tychay Post author

    @Braden Really sorry about the deletion. If I had marked it as SPAM, I could have recovered but delete was delete.

    Good point about onDOMReady (via $.ready()). If I’m designing an ad server, I might wish to still have the ads and such load onLoad instead. In YUI, at least, they also have onAvailable and onContentReady which are probably more appropriate for certain forms of DOM scripting. I assume they have those in jQuery?

    I wasn’t aware of the jQuery UI library. I might have been more aware of it if every tutorial didn’t espouse the base framework and if each page didn’t take over six seconds to load on Firefox. ;-)

    Reply
  8. Braden

    Not a problem.

    The documentation says that $(window).load() doesn’t fire until “the user agent finishes loading all content within a document, including window, frames, objects and images.” (The advantage over a plain window.onload being multiple bindings handling.)

    I’m not aware of an onavailable or oncontentready equivalent. I wouldn’t be surprised to see libraries moving toward event delegation for ultra-speedy bindings. (It’ll be as responsive as <input onclick=””>! The future is here!)

    Yeah, to be honest, jQuery UI isn’t half as mature as the base–they started fresh about a year ago. They’re putting a lot of focus into it right now, though. Frankly, I don’t think you give the core framework enough credit for saving developer hassle; $().ajaxSubmit() in particular is a beautiful example of abstraction from browser incompatibilities in Ajax and event handling.

    I’d be interested to look into those horrifically slow demos. I’d bet money, though, that the problem isn’t too many document.getElementById() calls. =)

    While I’m leaving a comment, by the way, I really enjoy your programming posts. +1 funny, +1 insightful. Thanks for blogging.

    Reply
  9. tychay Post author

    @Braden I don’t think the slowness is a problem with the Javascript, but a problem with the appserver. Something is really slow, especially when the content on the site is mostly static. I was just teasing about that part. ;-) But also implying something: PHP adoption, as ugly as the language is, is very fast because the docs are very extensive, URL searchable, and very, very fast.

    I wasn’t aware of $().ajaxSubmit(). I knew only about $.ajax() which seemed like Ajax.Request() in prototype. I haven’t decided whether the $ object as a namespace is a really good idea or highly annoying, yet. It’s definitely a clever idea.

    I’ll be the first to admit that there is a lot in jQuery I’m not familiar with. I sort of made my bed with YUI and live with it. Its Connection Manager is too lightweight relative to most, but it gets the job done with minimal hassle and not that many libraries are dependent on it.

    Thanks for your comments on my programming posts. I should mention that I often don’t mean half of what I say as harshly as I say it. Mostly I write those things to get people thinking about things, even if they don’t agree with me. The unwritten motto of this blog is: “Write to create context for another to think.” And I hope I do that.

    Reply
  10. Braden

    Wow, you’re right–the documentation is really slow. Remy Sharp’s jQuery API browser is a pretty good interface once it loads, but yeah, the PHP docs can’t be beat. (Especially with a Firefox keyword for “p” to “http://php.net/%s”.)

    $().ajaxSubmit is from the form plugin, so I guess it’s not jQuery itself, but the form plugin is only 8.3 KB compressed.

    It’s pretty easy to use “jQuery” as the namespace instead, but I’m a fan of fewer keystrokes.

    Reply
  11. PrettyCoder

    Sorry couldn’t resist:

    jQuery.noConflict();

    > for (var i in document.links) { // technically a for-do is marginally faster
    > var link = document.links[i];
    > if (link.class !== ‘external’) { continue; }
    > // better and more DOM scripted to replace the below with a YAHOO.lang.augmentObject
    > link.onclick = function() { return confirm(‘You are going to visit: ‘ + link.href); }
    > }

    jQuery(‘a[rel*=”external”], a.external’).click(function(){
    return confirm(‘You are going to visit: ‘ + this.href);
    });

    > $(‘#blah’).href = ‘http://www.example.com/';
    > $(‘#blah’).style.display= ‘none';
    > $(‘#blah’).style.visibility = ‘hidden';

    jQuery(‘#blah’).attr(‘href’, ‘http://www.example.com/’).hide();

    Reply
  12. tychay Post author

    @PrettyCoder: No problem! No need to apologize as you bring up an interesting point.

    To the first example. Nice catch with the “rel=external” instead of my use of “class” and it also points out an error in my code above since class is in the attributes of link. It should be links.attributes.rel with a match in there. However, I think you need to benchmark your jQuery version to understand my point (abstraction costs).

    To the second. As mentioned before, I wouldn’t code this way, I was trying to show how a shortcut will build a bad habit in a bad programmer, here is how I would code it.

    var link = document.links(‘blah’);
    link.href=’http://www.example.com/';
    var link_style = link.style;
    link_style.display=’none';
    link_style.visibility=’hidden';

    (The last three lines would probably be…
    YAHOO.util.Dom.addClass(link,’hidden’);
    sacrificing some speed for clarity (in markup, not in Javascript… big difference btw).)

    I suggest you benchmark that also, though the difference in this case will be minimal.

    On a personal (read opinionated) note, just because it is one line of code doesn’t make it any faster to execute, nor, in my opinion, more readable. It is the case with functional languages, and functional-style approaches, that it is quite often, slower. I have found that it is also less readable to others than more explicit approaches.

    It is, no doubt, much prettier. However, if I thought coding was artful, I’d be a perl coder.

    Reply
  13. Richard Crowley

    Just have to point out that $ to a PHP/Perl programmer looks like a variable but to EVERYONE ELSE it doesn’t. To JavaScript nerds it actually screams FUNCTION at them, so not a bad thing that all of the libraries use it.

    Reply
  14. tychay Post author

    …and to the shell scripter. Where did you think the choice of $ came from? I’ll hazard a guess it was because some PHP/Perl/Shell scripter was coding Javascript and found out that naming variables with $ still executed correctly.

    In any case, this hypothetical Javascript nerd is abstracted from the cost of the function, which is large in the case of prototype and extreme in the case of jQuery. In the case of jQuery it also “screams ‘namespace.’”

    YUI doesn’t use it. Neither does DojoToolkit. Showing that, in fact, the most popular libraries of today do not use this function.

    Reply
  15. David Mark

    Right on. The jQuery library is a terrible liability. Using it on the public Internet is madness. The browser sniffing alone ensures that.

    And those ridiculous patterns with the $ are often described as “efficient” by jQuery proponents. Oh brother.

    And then there is the “less code” nonsense. If you start out with a huge library, there isn’t much room for your code anyway.

    And its only 15K! Yeah, right. Even if it was, that is 15K too much.

    Anything to convince incapable people to take up browser scripting. You can’t miss the influence when surfing the Web these days.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>