Reputation: 997
I have written this piece of JS and CSS loading code and I would like some advice on it. Anything some of the Javascript Gurus could possibly point out would be much appreciated. The code works, but I have not done extensive testing, because I am concerned about replacing functions in this manner.
A single javascript file containing JQuery as well as the below code will be included on all the pages. We write all the components in house and keep them very modular separated into their own folder with the corresponding JS and CSS. You can imagine starting to use for instance a dropown, dialog and a datepicker on one page would require us to add 6 includes and this quite frankly is annoying, because I want the dependencies to resolve automatically and using JSP includes could possibly make multiple calls to the same resources.
Below is the src to load a single datepicker lazily
;(function($){
//All Lazily loaded components go here
$.fn.datepicker = function(settings){
console.log("This should only be displayed once");
loadCSS("/res/component/datepicker/datepicker.css");
var elem = this;
return loadJS("/res/component/datepicker/datepicker.js",
function(){return elem.datepicker(settings)});//After Load Completion the $.fn.datepicker is replaced
//by the proper working implementation, execute it and return it so we maintain the chain
};
}(jQuery));
function loadCSS(absoluteUrl){
if(loadCSS[absoluteUrl])
return;//Css already loaded
$('<link>')
.appendTo('head')
.attr({type : 'text/css', rel : 'stylesheet'})
.attr('href', absoluteUrl);//Appending entire element doesn't load in IE, but setting the href in this manner does
loadCSS[absoluteUrl] = true;//Memoize
}
function loadJS(absoluteUrl, onComplete){
if(loadJS[absoluteUrl])
return;//Script already loaded
loadJS[absoluteUrl] = true;//Memoize
var result;
jQuery.ajax({
async : false,//Synchronized because we need to maintain the JQuery chain
type :'GET',
url : absoluteUrl,
dataType :'script',
success : function(){
result = onComplete();
}
});
return result;
}
Upvotes: 0
Views: 139
Reputation: 5259
Have you looked in to Require JS, it will send async requests for only the modules you need for a given module.
In addition, because dependencies are scoped to the callback function, namespaces clashing is less of an issue
Typically you would have:
require(["jquery", "foo", "bar"], function($, foo, bar){...});
which allows your code to remain modularized both server side, and client side, in separate locations.
Of course, you need to set up require on your server with a config (described in the webpage), and wrap your resources in define blocks:
define("foo", ["jquery"], function($){...});
The downside is performance on pages that require many modules. In this situation you benefit more from having all resources in combined files, but note that query strings will cause the browser not to cache files in any case.. which is also another performance consideration.
Hope that helps
ps. In terms of CSS lazy loading, you could always use javascript to inject link tags into the head adhoc, and provide some javascript interface functions that your other code can call in order to request a CSS dependency dynamically.
Upvotes: 1