How Lazy Loading JavaScript Reduces Page Load and Optimizes Application Performance

If you’ve ever built a large JavaScript application in any of the popular libraries out there like jQuery or MooTools you quickly find yourself including a lot of different libraries. In a recent jQuery based application our team was using additional libraries like dataTables and MultiSelect. We also knew that we’d be using even more down the line. The traditional approach is to include everything all at once, especially in a single page application. Even in a multi-page application lots of developers stuff javascript sources in the header or near the end body tag. Since this was a fresh project I decided to look at some things like RequireJS so we only grabbed what we needed when we needed it as well as to manage┬ádependencies. RequireJS ended up seeming a bit too much to take on at once so I decided to roll my own solution.

Update Feb 22, 2013: I’m now using LabJS┬áto handle this.

Loading JavaScript

The addScript method accepts a script source such as “/js/app/my_script.js” and a callback function which is called once the script is loaded. Before loading the script it checks a resources array within the object to see if the script has already been loaded. A method for loading CSS creatively named addStyles performs a similar function as this.

Loading Libraries

I also wanted to make sure that whole libraries could be loaded rather than needing to call each JavaScript and CSS file individually. To accomplish this I created a lib.js file in each libraries folder. This file holds a simple array of paths to CSS and JavaScript files. To add a library I’d then call addLibrary(‘/js/lib/dataTables’,callbackFunction) and the method would read in the array from lib.js in that file and load all of the libraries resources. addLibrary also supports a callback method to execute specific code needed by the application once the library is loaded.

Single Page Feel

We wanted to have a single-page application feel without everything being a single page. To do this we stuck with a standard MVC server-side framework (in this case CakePHP). On the front end a simple method would handle fetching the server side control/view. That same function also loads in the script. To make things easy we went with a convention of having the server-side controller and the javascript file share the same name.

Example Usage

Speed

This is noticeably faster than some of the other ways of doing this described at the beginning of the blog. Each portion of the application only loads what it needs and the application will only ever load something once. There is nominal overhead in keeping track of whats loaded. The only addition I could see necessary is analyzing what scripts are kicking around in memory after they are no longer being used and getting rid of them somehow without requiring a full reload of the script when they are needed again.

Limitations

There are some limitations with this design. It could lead to stuffing way to much into a controllers javascript file. I feel like some refactoring will be neccessary down the line to split things up should things get out of control. There will definitely be a need for separating concerns in the client side code. Still, I think this is a solid solution that everyone on the team understands. The alternative was too learn a full blown JavaScript framework like Sencha/ExtJS (no thank you) or use a combination of libraries like Backbone, Underscore, and RequireJS. Since everyone on our team is comfortable with jQuery, this seemed like the least invasive approach and we’re pretty happy with the solution thus far.

Other Thoughts

I’m still interested in what things like Backbone or even Ember can offer, but it just didn’t make sense to introduce a bunch of new technology to a critical application without having an expert on the team.


5 Comments

  • Svend T says:

    I dont know your application of course, but you might hit some serious limitations with your approach if you want to take it very far, as the controls loaded like this will have no events wired or anything, and with complex/nested controls/templates/whatever, proper initialization can become extremely complex.

    • chris says:

      Our events are working fine. I don’t understand. Your right on initialization though, I’ve already had to refactor how controls are loaded once so they utilize callbacks to get everything working properly.

  • Brice says:

    nice but still it has dependencies on JQuery which remain pretty big. We use LAB.js ( http://labjs.com/ ) simultaneously load interdependent scripts. On personal project I like having the compressed version of script.js by Dustin Diaz directly in my HEAD (http://www.dustindiaz.com/scriptjs) to prevent any blocking request while page is loading. Otherwise I tend to agree on the technology as long as those projects are short terms one. I maintain only one large project where milliseconds (seriously milliseconds) gets converted in hundreds more users per day, so we had to overcome the technology comfort barrier and go with what’s fast.

  • O.S. says:

    Hi Chris,

    You may want to take a look at a recent project I added to Github, you might even find it interesting to mention:

    https://github.com/orientalsensation/lazy-js

    Feel free to incorporate a link on your page.

    Thanks in advance, and keep up the good work!

    /OS