jqueryhtml5

in JS

Native equivalents of jQuery functions

Update: many people have asked about browser compatability for the native methods I’ve shown. Here are the links to that information: querySelector/querySelectorAll, classList, getElementsByClassName, createDocumentFragment.


If you checked out my last post you’ll know that I have been doing lots of JavaScript coding as of late, both inside and out of Brackets. I have also been doing a series of performance tests (1, 2, 3) between popular jQuery methods and their native DOM equivalents.

Yes I know what you’re thinking. Obviously native methods are faster because jQuery has to deal with older browsers and host of other things. I completely agree. That’s why this post is not meant at all to be anti-jQuery. But if you are able to target modern browsers in your work, using the native C++ methods provided by your browser will not-surprisingly give you a tremendous performance boost in most areas.

I think there are many developers who don’t realize that most of the jQuery methods they use have native equivalents that require the same or only a slighter larger amount of code to use. Below are a series of code samples showing some popular jQuery functions along with their native counterparts.

Selectors
Easily being able to find DOM elements is at the core of what jQuery is about. You can pass it a CSS selector string and it will retrieve all of the elements in the DOM that match that selector. For the most part, this can all be easily achieved natively using the same amount of code.

DOM manipulation
Another area where jQuery is used frequently is in manipulating the DOM, by either inserting or removing elements. To do these things properly with native methods, you will definitely have to write some extra lines of code, but of course you can always write your own helper functions to make things like this easier. Below is an example of inserting a set of DOM elements into the body of a page.

CSS classes
It is very easy in jQuery to add, remove, or check for the existence of CSS classes on DOM elements. Luckily it is just as easy to do this with native methods. I only recently found out about these myself. Thanks you Chrome DevTools.

Modifying CSS properties
The need to programmatically set and retrieve CSS properties using JavaScript comes up all the time. When doing this it is much faster to simply set the individual styles one by one rather than passing them all to jQuery’s CSS function. It really isn’t any additional code either.

Remember, jQuery is an amazing library that makes all of our lives easier. But you should always choose to use native DOM methods if they are available to you. This is especially true if you are using jQuery inside of loops or timers.

Now of course, I have been hanging around game developers for a while now so maybe I’m a tad over-sensitive about performance. In that world if your game doesn’t run at 60 FPS, you might as well go work at Target. Anyway, hope this post helps some folks!

Write a Comment

Comment

68 Comments

  1. Thank you Lee, this is an excellent article to realize it’s not over complicate to go one step further in the code :)
    It’s that kind of article i was looking for in the early days of AS2->AS3

  2. great post, and very topical. did you see any of the Chrome perf tuning sessions from IO – targeting 16.5ms and reducing painting means cutting down every wasted cycle to create great jank free experiences.

    I wonder if there’s a way to build a simple tool to switch some of these jQuery patterns to raw JS – use feature detection to decide if it loads the jQuery or native solution

    • No I haven’t seen it. Still need to watch all of those. Yeah I think you could have one JS file for older browsers with jQuery and another using the native stuff.

    • “I wonder if there’s a way to build a simple tool to switch some of these jQuery patterns to raw JS ”

      Things I don’t think you’ll like very much:

      – DOM methods that return Live NodeLists. (getElementsByTagName, getElementsByClassName)

      – thrown exceptions when their dynamically generated selectors are invalid.

      – null returns

      – slicing every NodeList and caching its length before iterating (it’s real slow and bad if you don’t)

      – making multiple classList.add/remove calls for multiple classes-at-a-time (this will eventually not be true, but it will be a while before all browsers have caught up)

      Anyway, I hope you get all the Google juice you hoped for.

    • Where appropriate, jQuery uses the native implementation of the method. For example, jQuery.now() === Date.now(). No indirection. And with jQuery 2 removing support for older browsers the library has experienced about 20% reduction in file size. It also uses new and better DOM methods. Before you throw in another jQuery method call, just spend a minute or two inspecting the code (you can benchmark it even) to see which parts will be unnecessary for you.

  3. Do you know jslint? If not, it’s sometimes worth to let it “take a look” at the written JS-Code:
    http://www.jslint.com/

    Also worth some exploring is jsPerf: http://jsperf.com/browse

    There are sometime big differences in performance, depending on which browser is running the js, and how the code was constructed, indepentently of if one is using jQuery ore native JS.

    I’m looking forward for more JS-stuff to come from you, Lee. ;-)

    Regards Paddy

    • Yeah I’ve used Lint before but I couldn’t figure out how to only show certain stuff. There were like thousands of results in SublimeText when I ran it.

      As for JSPerf, I’m addicted to it. See the 3 links to performance tests in the first paragraph of the blog post.

      • Hi Lee,
        You can just add options to disable multiple JSLint options at the top of your file. You can also have a look ar JSHint which is a fork of JSLint and has options to easily disable syntax highlighting, indentation and others to adjust to your needs.

      • JSHint (a fork of JSLint) allows you to customize your results without conforming to Douglas Crockford’s rather opinionated view of how to write JavaScript code.

  4. I don’t think you can be over zealous about performance when the world is going mobile… time critical code needs to be fast and if that means native then devs should know the above methods, great post, keep em coming!

  5. Great article, Lee! Do you have any experience with jQuery 2.0? Since it got rid of all that legacy code the performance should be way better. I was wondering how close to the native functions you can get with jQuery 2.0. Cheers, Simon

  6. I made a micro selector library that maps jquery-style selector methods to the native DOM equivalents. I have some jsperf test, and it always beats querySelectorAll.

    The nice thing is you don’t have to write out the massive method name wash time. You can use jquery syntax :)

    https://github.com/james2doyle/saltjs

  7. Thanks for this article!

    You acknowledge there are compatibility issues but don’t mention what browsers support each of these functions. Are these functions common to IE9/Firefox/Chrome/Safari/Opera or is it a little more complicated than that?

    It is also worth mentioning that these functions didn’t exist when jQuery began – the browsers caught up to jQuery, not the other way round!

    • Yes, the article is lacking.

      No, it is not worth mentioning nonsense about how browsers caught up to jQuery. The *only* methods that could be (and wrongly as it turns out) attributed to jQuery are selectors-related. And, of course, jQuery dropped the ball back around 2008 when it turned out that the new browser standards weren’t quite compatible with jQuery. So jQuery is still not compatible with (for example) QSA. Bad news as they try to use QSA internally as a faster “equivalent”.

      No, jQuery did not invent add/remove/hasClass functions or appendChild methods or… anything really. They didn’t even invent CSS selector queries (just completely screwed them up).

    • Basically the stuff I showed works in the latest releases of all of the browsers. Again like I mentioned, I’m pointing these out for two reasons. One, many people are doing creative HTML5 stuff where they can target these latest browsers. Secondly, it’s good to know what jQuery is doing behind the scenes.

      I still use jQuery all the time so I’m not hating on it.

    • “To partially answer my own question, it looks like querySelectorAll is very widely supported, even on IE8 as long as your selectors are CSS2″

      But not compatible with jQuery’s crap. :(

      https://groups.google.com/forum/?fromgroups#!topic/comp.lang.javascript/-ANFImIZ1CQ

      When using basic selectors (e.g. ‘div.myclass’), you are creating speed bumps for no good reason. Save ten seconds typing and delay every user click, focus, etc. forever. Could just as easily use a simple gEBTN (or gEBCN) wrapper.

      Using more complicated queries just marries very specific document structures to your scripts, which is the last thing you normally want.

      Realize you have to test whatever sorts of queries you plan to use. jQuery can’t do that for you; if fact, it just gets in the way. If your app is to degrade in older IE browsers (for example), you can just test QSA. If you get the wrong number of elements (or catch an exception), you don’t launch your app (or the part of it that relies on those sorts of queries). No need to memorize which versions of which browsers do what.

      Main point to take out of all this is that jQuery is virtually worthless (at best). That’s really always been the case, but it’s more noticeable now.

      • Sounds like someone likes to read and preach but not actually develop. While you could make your mark up much more complicated to handle situations where you would like to select elements by means that are not compatible with older versions of IE that us folks out here actually doing work still have to support (for instance any css3 selectors) frameworks like jQuery are the obvious way to do this. Sure, I could waste tons of my, or my clients time writing native code, and iterating over the DOM, or I could use a framework like jQuery and handle cross-browser compatibility issues for me for selector support, ajax, class manipulation, etc. The few extra milliseconds it might take jQuery over specific native code is never going to be noticed by the user for 99% of applications, and the code will be much cleaner and more simplified. So why don’t you hop off that white tower and come join the real world.

  8. It’s a nice start, but you should really also consider adding to this list browser support. To wit:

    .querySelector/All() isn’t supported by ie lte 7
    .getElementsByClassName() isn’t supported by ie lte 8
    .classList.remove()/add()/contains() isn’t supported by ie lte 9

    This is why people use standardized libraries. Frankly, if it’s not supported back to IE 7, I’d be hesitant to use the native function at all.

  9. I find that when I try to use native equivalents, I end up writing a lot of extra code to account for inconsistent browser implementations found during testing, which jQuery, EXT, dojo, … already test for and support.

    I cannot see native only being an option, without being a huge test burden, unless the code only has to support a limited number of browser+version combinations.

    • Absolutely. That’s what is so great about jQuery. But many things are being built in JS now require the latest HTML5 features so if you’re doing that kind of work then native is the way to go.

  10. One “gotcha” that jQ protects you from is that getElementsByTagName and getElementsByClassName return live NodeLists.

    For example
    var divs = document.getElementsByTagName(‘div’);

    What “live” means is that each time you use the divs collection, the DOM is interrogated again. As a result, code like the following will not only interrogate the DOM each time you use divs.length, but will create an endless loop because you’re adding a new div on each iteration.

    for(var i=0; i<divs.length; i++) {
    document.body.appendChild( document.createElement('div') );
    }

    document.querySelectorAll however returns a static NodeList (which is why it's slower) and is safer to use (though not supported by <=IE7).

    • Yep I totally forgot about that difference. Maybe I’ll do a separate blog post explaining that. Thanks!

  11. I think it’s noting that while using native JavaScript is relevant, knowing it is imperative.

    That said, the performance “loss” associated with jQuery’s abstraction layer to help address all browser’s nuances (especially Internet Explorer) just took on a major improvement with jQuery 2.0 …

    jQuery 2.0.x is the same as 1.9.x and eliminates legacy IE support. You’d want to use jQuery 2+ when working on mobile sites, for example. And in a case like that, you’re going to realize some benefits from leaner code that no loger has to think about olden browsers.

    • In the performance tests I’ve done with jQuery 2 it is indeed much better on performance. With that being said the native methods are still between 50%-70% faster.

    • You think of a DocumentFragment as essentially a temporary DOM container. Every time you add something into the regular DOM it cause something called reflow. This is quite expensive performance-wise. With the fragment you can add 10 div elements to it and then add the fragment to the main DOM. That way you have only triggered one reflow. jQuery does this behind the scenes if you use functions like append().

  12. Howdy,

    I just wanted to say you might make a note was to WHY someone would want to use document fragment instead of just appending to the DOM. It’s something that yields in an incredible performance gain (especially when you’re iterating through an array of html to append); and if more people knew about the why of it, I’m sure they’d use it.

    Good article, thanks for sharing the info.

        • Using your test suite:

          In Chrome, it’s fastest (28% faster than appending to the DOM)
          In Firefox, it’s also fastest, but only by a touch (4%)

          However, in IE10, it’s only a touch faster than jQuery, and appending HTML is more than twice as fast as using document fragments.

          The only thing we’re sure of is that either native method is faster than jQuery.

    • Yeah see my reply to Bobby above. I’m going to write a separate blog post on about that as it might get kind of lengthy :)

  13. That’s completely ridiculous. In fact, you should do quite the opposite as different DOM features have different levels of support. This is a surefire way to get browser incompatibilities. By leveraging jQuery you can write code once, not once for every browser version/os combination.

    If you really want to leverage the power of both world, contribute to jQuery and have it use the native methods when available. That is trivial and jQuery already does a lot of this. Have you looked at the code?

    We’re still trying to figure out cross platform apps and eliminate the development time for the three or four major OS’s while you are advocating writing code targeting literally hundreds of platforms with now wrapper around them.

    The problem with JS is not that it’s a bad language per se: it isn’t. It’s just too powerful and thus leads to mostly misuse and misunderstanding along with a whole lack of concern about repeating history’s mistakes (see C and C++ porting of any non-trivial app, especially GUI).

    • Perhaps you need to re-read what I wrote in the post. Do you think everyone who uses JavaScript is using it to build websites? With HTML5, a lot of work is being done to use JavaScript for things like games, complex animation, and many other things. If you are doing that kind of work then you will suffer large performance hits if you’re using jQuery. And let’s not forget about mobile where JS is being used for apps, games, etc.

      Apparently you missed the part where I said that jQuery was vital to building websites and that I use it all the time. Relax dude.

      • Perhaps you need to re-read what you wrote in the post? ” But you should always choose to use native DOM methods if they are available to you.” And I strongly disagree with that. Clarity first, the speed *if necessary*. In game inner loops, sure – but even in a game, 80% to 90% of code is going to not be time sensitive. Spend your effort where it makes a difference. Count cycles in your inner loop, and don’t care about the small stuff.

        Also, “For the most part, this can all be easily achieved natively using the same amount of code.” is just wrong – you follow this with a first example showing almost 5x more code for the native variant compared to jQuery, and with your best for native code example showing 1.6x more code for native compared to jQuery.

      • While I don’t disagree with your assertion about the speed benefits of native DOM methods, I feel there’s an elephant in the room which is not being pointed out in regards to writing games using JavaScript.

        That elephant would be canvas, and learning how scene-graphs work (becuase canvas is a dumb output context) the developer is responsible for designing amd implementing the scene graph. To write games of any visual compelling consequence with good performance requires understanding graphics buffers and writing collision detection algorithms, all of which have nothing to do with jQuery and everything to do with standard hardcore computer science principles. Take the work being done on asm.js as an example: typed arrays, webGL which is even more complex to work with than canvas.

        Again this is unrelated to jQuery but very relevant to writing games using JavaScript. The language isn’t the problem, the challenge is similar for developers of any classical language, how to write fast and effective algorithms that deal with useful while-efficient (that’s a tradeoff usually) data structures in game.

  14. As long as our customers use Internet Explorer 7, the best solution for business – is to use jQuery. And although it is slower, it is not so slow, that it felt by users :) But in general, you’re right, now people are using jQuery for even the most simple things. Sorry for bed English.

  15. There is also el.classList.toggle(‘myClass’) that equates to $(el).toggleClass(‘myClass’) but it doesn’t support the second arg that jQuery’s toggleClass supports

  16. Shorter (&IMO better) native equivalent for setting multiple CSS styles;

    element.style.cssText = ‘background: “#FF0000″; width: 100px';

  17. As a native equivalent of event handlers, is this a good / safe to use by extending element prototype.

    Element.prototype.on = function(ev, cb){
    this.addEventListener(ev, cb);
    }

    So we can do.
    var el = document.querySelector(‘#id’);

    el.on(‘click’, function(){ alert(this.href); });

    or Simpley

    el.addEventListener(‘keyup’, function(){ console.log(this.value); });

  18. Use Zepto, much better than the spaghetti you would write above – except if you prefer speed over readability.

  19. There’s also forEach, an equivalent to $.each but only for arrays.
    For those who can’t stand writing document.querySelector, here’s a quick function :

    function $(el) {
    return document.querySelector(el);
    }