Pages

Friday, December 6, 2013

Optimizing page loads by reducing the impact of Javascript initialization

So you combined all your Javascript files in the hope it will speed up page loads ? Well for sure the download will be faster, but the browser still needs to execute all this Javascript ! There are simple tricks to help reduce the impact on page loads.

Reduce DOM queries and manipulations

With libraries like jQuery, it is really easy to bind all sorts of events on complicated selectors. The thing is, the browser has to query to DOM like a mad man to find out all elements. Things get even worse when you add elements or query information like height or position, which triggers reflows and repaints. Try to be minimal.

Make initialization conditional

If you have a big block of code that needs to be executed only in specific cases.
  • Add a class to the body element and verify it.
    Ex: jQuery(document.body).hasClass('user-logged-in');
  • Check existence of important sections.
    Ex: document.getElementById('comments');

Delay initialization of non-essential parts

  • Delay heavy libraries like Google Maps or Facebook Like.
    See this post about loading social libraries.
  • Use requestAnimationFrame for animations.
  • Use setTimeout(function(){}, 1); to push the execution to the async queue, delaying the execution.
  • Use Web workers to run the function to run in background, without hanging the rest of the script. This also leverages multithread processing.

Use delegated event listeners

jQuery offers delegated event listeners where the listener is on an ancestor element. Your favorite library probably has it as well.

A good example is reply buttons in a comments thread: 
jQuery('#comments').on('click', '.reply', function(){});

How it works is that the click bubbles up to the comments element and there it verifies if the originally clicked element matches the selector.

This is extremely beneficial because you have much less DOM query at load and less event listeners to attach.

Initialize only on first use

Let’s say you have a complicated modal dialog that needs initialization and this process may take about 50ms. This is not very noticeable, but if you have other things to do after, you may well get over the 100ms rule, so you wouldn’t want to do it every time a modal is popped. For the same idea, you wouldn’t want to initialize 2-3 of those things at page load. This is why you need setupOnce

Inspired by the once function from Underscore, this utility will group two callbacks: one that is ran the first time it is called and only that is called every time.



Mobile

Mobile is even more critical because 200-700ms is spent doing the initial HTTP connection. For an in-depth look, see this presentation by @igrigorik from Google.