Search

  1. Javascript code performance review

    Within the scope of my latest projects, I had to review a lot of performance details on JavaScript to determine best possible solutions for core functionalities and architecture.

    If you follow the classic “by the book” rules, you should avoid, when possible:

    1.  loops
    2. closures
    3. object spawning
    4. DOM access, specially DOM writes
    5. DOM queries (find DOM objects)



    Ok, but how bad is it?
    How do they compare to each other?
    What options do I have?
    Which are the best ways to get the same result?

    This study focuses on answering these questions as best as possible in order to achieve an approximate scale on comparative performance results in JavaScript. 


    1. Loops 

    It’s easy to intuitively understand unrolled loops are faster than having the loop itself. However for ease of development, we sometimes tend to use unnecessary loops for common tasks;

    Take a look at http://jsperf.com/unrolling-loops

    You can see the difference between running direct code vs doing the same in a loop is massive, really massive.
    Of course the unrolling above is way too much work unless you have a system where performance is hugely more important than anything else - including a huge file size…

    But the overall point is, if it takes you only 3 or 4 more lines to do it and it doesn’t involve extra functions call, etc, it’s probably better just to unroll the loop. 



    2. Closures 

    Look at this example: http://jsperf.com/closure-vs-no-closure

    Free code is, as expected, faster, followed by the function call and finally the closure. However the gap between each use case performance varies between implementations, we can see Chrome running free code much, much faster than having a closure, while other browsers can have a very close match between all use cases.

    So what does it mean?

    in average :
    - closure - slowest!
    - function call - 2x faster than closure;
    - free code - 4x faster faster than closure;

    Finally I’ve confirmed this performance test in a practical case testing loops against “forEach” callbacks in http://jsperf.com/loops-vs-each-callbacks

    You can see regular loops perform twice as fast, as expected.
    To put it in perspective this means running the function call alone, takes about the same time to run as this example’s entire loop. 



    3. Object Spawning 

    Take a look at http://jsperf.com/instance-vs-object-create/4 

    We can see the new ECMA5 Object.create is, in average, as fast as instancing a new object from a function, with the exception of Chrome where instancing a function is clearly very, very optimised, along with creating direct object and arrays - actually, this is one of the reasons why JavaScript “is” so fast in Chrome.

    As you can see, instancing is still faster than using a closure, about 2x faster more or less the same as a function call (by our previous example; But it will probably be much slower if you have a big prototype.

    However be aware that creating an object or array directly actually takes longer than instancing, even if you use an interim functional call to get rid of the “new” keyword (eg. jQuery’s $()).

    To conclude I would say it is ok to use instances and objects altogether, however if there is something which can be easily done through simple function calls instead, use them. 





    4. DOM Access - read and write 

    Ok, this is a big one.

    Let us start with an overview of the most common tasks: http://jsperf.com/dom-read-vs-dom-write/2 

    You can immediately identify that using single style reads and writes is much slower than using CSS classes, and, as one would expect, using computedStyle is always slower than regular reads and style writes are the absolute slowest - in fact, changing the same property via class is about 4x faster then a style.property write.

    But wait a second!
    setAttribute and getAttribute are incredibly fast!
    Let’s play around with them a little bit more and check out what is better/worse 



    4.1 Data API : attribute vs .dataset  

    You can see by the previous test results that using attributes is way faster.
    Clearly dataset.data hasn’t been optimised yet. 

    However it is very likely as its use becomes more and more common, .dataset will very likely be optimised too.



    4.2 attribute class vs .className :  

    http://jsperf.com/classname-vs-setattriubute-getattribute

    Fairly close, but .className is still a faster solution, attributes loose in this case; 



    4.2.1 Extra: classList vs .className:

    http://jsperf.com/classname-vs-classlist-showdown/2

    Serves to show if your browser supports ECMA5 standards, classList is highly optimised;
    Use it.



    4.3 style.property vs setAttribute style 

    http://jsperf.com/style-property-vs-setattribute-style

    Ok, style is clearly optimised vs setAttribute use as expected, except…
    Wait… What?!
    What the hell is up with firefox??
    Why is it so fast?

    I double checked and it actually changes the style as expected, it really works! And it appears to be 4x faster than using style.property on all other browsers…
    A setAttribute(“style”) + computedStyle read in Firefox is still faster than a style.property read in chrome!
    There is something really strange going on here… - if anyone can explain why this is happening please let me know in the comments.

    So overall writes are indeed slower than DOM reads, but not that slower. Actually getting the computedStyle takes much longer that a write.

    So: avoid computedStyle reads, and if you do it, try doing it only once until you actually change it again. 



    DOM queries and selectors 

    Lastly, the DOM query selectors, here are the results: http://jsperf.com/dom-queries

    When can clearly see the advantage of always using document.getElementById as it is twice as fast as any other option.

    If you cannot rely on a specific id but are still just looking for one item, use querySelector as it is, for the most part, the second fastest option.

    If you really require more than one items returned, consider first if you can use document.getElementsByClassName, and only use querySelectorAll as a last resource.

    Remember that having up to 5 or 6 getElementById calls is still faster than a single querySelectorAll call. 
    Use it wisely. 





    Comparing them all together 

    For the sake of fully grasping the concept, I have combined a jsperf with a mix of a few results above and put them all against each other.

    Here it is: http://jsperf.com/mother-of-comparisons

    The results table:

    Jsperf results table

    So, as you can see, messing with CSS things always cost you the most, no matter what. All code you can do is fairly insignificant comparing to it, but if you want to go into performance details, here you have it:





    Results: (best to worst)

    1. Simple code & functions
    2. Closures
    3. getElementById
    4. instance new Object
    5. messing with DOM objects without reflows* - most attributes, etc
    6. querySelectorAll
    7. messing with DOM objects that triggers reflows* - CSS, classes, etc


    1-5 everything is pretty fast

    6-7 avoid when possible (at least 20x slower than 1-4)



    * Note: reflows is, in a simplistic view, when the browser has to redraw all or part of the page - more on this later ;)

Notes

  1. travisspencer reblogged this from 9treeblog and added:
    Tips and advice to keep JavaScript soeedyy
  2. carlos-ouro reblogged this from 9treeblog
  3. 9treeblog posted this