If you follow the classic “by the book” rules, you should avoid, when possible:
- object spawning
- DOM access, specially DOM writes
- 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?
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.
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
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 :
Fairly close, but .className is still a faster solution, attributes loose in this case;
4.2.1 Extra: classList vs .className:
Serves to show if your browser supports ECMA5 standards, classList is highly optimised;
4.3 style.property vs setAttribute style :
Ok, style is clearly optimised vs setAttribute use as expected, except…
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:
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)
- Simple code & functions
- instance new Object
- messing with DOM objects without reflows* - most attributes, etc
- 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 ;)