Front-end optimizations you can start doing right now

I would strongly suggest to any serious front-end developer to (really) learn JavaScript and understand the basics of DOM. Of course, some may argue that many JavaScript-specific hacks and tricks do not have much impact on performance as perceived by the final user, and I completely agree. That being said, in this article I’ll share some techniques that you can implement right now on your current code base to make it faster, and from now on, you should have them in mind whenever you write JavaScript for future projects.

Use selectors wisely

Let’s say you have a div with certain id #profile-container, and you need to get one or more input elements with the class “myClass” inside the div. You may quickly come up with a jQuery selector like this:

This get the work done, but it may not be the best way to do it. In fact $(‘#profile-container’).find(‘input.myClass’) would be faster. The reason for that? How JQuery selector engine works. Basically, a $(‘#profile-container’) selection would be pretty fast and straight forward to make, and whenever you chain the function find(), it will be restricted to a very limited search space, improving the performance in general. Take a look at JQuery source.

In this article written by Rob Tarr you’ll find some experiments and tests that validate this point. Even more, the author found out that is even better to chain find() calls, for instance, $(‘.container’).find(‘.main’).find(‘ul.list-1′).find(‘li’)

Selectors summary results from seesparkbox.com

 

Another wise way to improve JQuery selectors performance is to explicitly declare the element type we’re looking for, in case we know it before hand. This, $(‘ul.todo’) would always be better than $(‘.todo’) on reasons of element specificity.

Cache jQuery selector results

This one is very well known, because of the classic reasons of performance, “don’t repeat yourself” and best practices. In Greg Franko’s excellent slides “jQuery best practices”, we find an interesting example:

The problem is that every time you call $(“.container input#elem”), jQuery needs to search for your selector, which potentially means traversing all the DOM. In this case, the look up for “.container input#elem” would be performed four times! You can very easily rewrite it as:

Check out we’re also using selectors wisely, as we’re looking for an id, there’s no need to loop up after a class or element in particular. #elem is easier and way faster.

Cache .length property

In JavaScript, every time you call the property .length of an Array it will be calculated for every time you try to access it. So, if you have something like

Should the size of myArray happens to be 10,000, the value of myArray.length will be computed 10,000 times, once for every loop turn. This would be much better:

Henceforth the value of arrayLength will be calculated only once.

Does this matter? In modern browser the difference is absurdly minimal, as their JavaScript engine already do this sort of optimization. Should you forget completely about it? Well, according to Thomas Lahn from comp.lang.javascript newsgroup:

One should never rely on what one cannot know. You cannot know the runtime environments code once written will be exposed to. There is no good reason to assume the value of the “length” property should be automatically cached for a loop in the first place as it could change by statements in the loop.

One can know instead that avoiding to access a property repeatedly whose value does not change, in favor of a local variable that holds this value, reduces code complexity. That has a chance – and it has been showed – to increase runtime efficiency, IOW to be faster. So it is wise to do that.

 

Minimize DOM operations

Writing into the DOM is a heavy operation. Remember: the DOM is slow and if you’re not aware of that, you’ll be stuck in performance issues sooner than later. This represent a classic example of a very heavy operation for the browser:

In that example, we’re reading and writing the DOM in every forEach cycle. You can avoid mass element injection by storing your nodes into a variable and then inject them in the DOM after the loop is done, hence appending only once:

Avoid repeated object creation

If you create an object inside a function, always keep in mind that object will be created every time the function is invoked. This might not be want you really want, specially when your object is static and it’s not expected to change over time. Consider this example by David Walsh:

The literal notation // is a shorthand for new RegExp, so every time you call something like /ab+c/ you’re actually creating a new RegExp object:

In our example function, we don’t really need to create a new regular expression object everytime, you we can actually create it outside the function and access to it through a closure scope:

Delegate event listeners

Assigning event listeners to individual elements may take up a lot of memory and is expensive if you create lots of new elements dynamically to which new event handlers need to be bound.

If your #todoList has 10,000 li elements that would mean 10,000 event handlers. Event delegation replaces the need for adding event listeners to individual items by instead placing one event listener on a given parent. The example above can be rewritten as:

Event delegation is even easier with jQuery:

Stop using jQuery when you only need selectors

We know, JQuery is the best tool to traverse the DOM, but if your project is only using jQuery for this solely purpose, you have to wonder if it’s really worthy to load an external library when we have document.querySelectorAll, which performs basically the same selector fetching operations as JQuery. Yep that’s right, you can use a native browser implementation to do all your daily selector tasks, such as document.querySelectorAll(‘.content ul li’). Is it long and ugly you say? Well, take a look at the example provided by Burke Holland in his article 5 Things You Should Stop Doing With jQuery:

In this way you can still use your loved $(‘mySelector’) syntax.

How faster is querySelectorAll compared to jQuery selectors? More than five times depending on your browser. Although JQuery would automatically delegate to document.querySelectorAll if present, you would still ponder if you really need to load those ~90kB.

 

Do you want to keep learning? I would recommend learning about profiling and managing data structures efficiently in JavaScript, I might write about it in the future, but in the meantime take a look at this article.
 

  • James

    Hey, I think the example with regular expression is wrong. var re = /ab+c/ is not equal to re2 = new RegExp(“ab+c”). Also I don’t find this information on mdn. Am I right, or I don’t know something?

  • James

    You are right. This is from ecma spec:

    A regular expression literal is an input element that is converted to a RegExp object (see 15.10) each time the literal is evaluated. Two regular expression literals in a program evaluate to regular expression objects that never compare as === to each other even if the two literals’ contents are identical. A RegExp object may also be created at runtime by new RegExp (see 15.10.4) or calling the RegExp constructor as a function (15.10.3).

  • http://www.odiseo.net/ odiseo42

    Hello James, thanks for pointing out the EMCAScript specs. Here’s from the MDN docs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

  • bebraw

    Good tips! Thanks for sharing.

    Is a contextual selector (ie. $(‘input.myClass’, ‘#profile-container’)) equal to $(‘#profile-container’).find(‘input.myClass’)? Normally the context is stored into some variable and it reads better. Just wondering. :)

    There’s a small typo at “if(e.target && e.target.tagName == ‘LI’) {“. Might want to fix that.

  • http://www.odiseo.net/ odiseo42

    Yes, a contextual selector $( selector, context ) is actually turned into a find() method internally: $( context ).find( selector )
    Check out a broader explanation here http://www.bennadel.com/blog/1876-Your-jQuery-Selector-Context-Can-Be-A-jQuery-Object.htm
    Typo corrected ;)

  • Vitaliy Petrychuk

    Nice tips! Another one bunch of suggestions I would recommend to read http://remysharp.com/2013/04/19/i-know-jquery-now-what/