Extreme Lazy-Loading for JavaScript: jQuery OnDemand
Too often web developers do not spend enough time and effort on making sure the applications they build are optimized in terms of performance. Two of the aspects that are often neglected are the number of HTTP requests an application makes to a web server and the amount of code that has to be downloaded by the browser for the application to work properly.
Frequently, we (yes, I have done this, like everyone else) just drop into our HTML several script tags and jQuery plugins, only because at some point we’ll need a specific functionality or some UI widgets. But what if the user never engages in the workflow that leads him to actually use that functionality or see that widget? That code would have been loaded for nothing, wasting bandwidth and possibly slowing down the download of other, more critical components.
I believe that for applications that go beyond a simple website with some animations and some simple user interaction optimizing the code and reducing as much as possible what the browser has to download is very important. Even more important if the application targets mobile devices.
For these reasons I created jQuery OnDemand, a small (~1KB) jQuery plugin to load features (Objects and Functions) only when needed. The source code, some documentation and examples are available on the jQuery OnDemand Github repository.
What the plugin does is loading a function or object only when required. All it is needed is a slight change in the invocation semantic, although I am planning some improvements that will make this unnecessary.
This is what invoking a function through jQuery On Demand looks:
$.onDemand.invoke('showPhoto', null, this)
The plugin checks to see if a function called showPhoto has been already loaded, and if not will take care of determining the file containing such function and download it. In the meanwhile a Promise is returned to the caller. Once the function becomes available it will be invoked and the Promise is resolved with the result of the function call. The function is then cached so it is available for the next invocation.
Similar work was done more than a year ago with Lazy, a lazy loader for jQuery plugins. jQuery On Demand goes a little beyond that, allowing developers to load on demand any function or object.
I am planning to create a build tool that based on annotations in the code will determine how to better split a source file into multiple, smaller files loaded by On Demand and automatically create a stub always delivered along with the plugin code so the invocation semantic does not have to change, although the use of promises will still be required.
Of course for the plugin to be useful and actually improve the performance of an application the developer needs to think smartly and find the right tradeoff between loading everything always on demand and delivering all the code in a single big JavaScript file.
Update
jQuery On Demand has now a build tool. The tool is a nice build script (requires Node.js) that creates the *-ondemand.js files and related loading functions from a properly annotated JavaScript file. The tool is still in early stage and needs to be improved and become smarter but it gets the job done.
This is a description of what can be done with the build script by adding some annotations to a normal JavaScript file:
// @all
/*Block of code*/
// @endall
Includes the block of lines that follow it in each of the *-ondemand.js files.
// @function (group=<GROUP NAME>,name=<FUNCTION NAME>,namespace=<NAMESPACE NAME>)
/*Block of code*/
// @endfunction
A function is considered as a unit, and may potentially be the only piece of code contained in a *-ondemand.js file. If a group is specified, objects and functions of the same group will be contained in the same *-ondemand.js file.
// @object (group=<GROUP NAME>,name=<OBJECT NAME>,namespace=<NAMESPACE NAME>)
/*Block of code*/
// @endobject
An object is considered as a unit, and may potentially be the only piece of code contained in a *-ondemand.js file. If a group is specified, objects and functions of the same group will be contained in the same *-ondemand.js file.