# On demand JS loader review

At my work, I need to create a script that third-party webmasters could include in their pages without need to include something else. But this script had dependencies on jQuery and some amount of their plug-ins.

On the Internet, I have found libraries that have same functionality except for an important one: they don't check are needed library already exist on a page.

Yes, I could execute the needed libraries in local scope of my script, but I've decided to reduce the number of HTTP connections and traffic with this function:

var require = function (lib, obj, libs_obj) {
// if obj is function than require called directly by user and we
// must transform it to object. It's for reduce number of used
// variables. When we call require recursively, we use this object
var lib_is_list = typeof(lib) === 'object';
if (typeof obj === 'function') obj = { callback: obj, count: lib_is_list ? lib.length : 1 }
if (lib_is_list) { // this is list of libs
for (var i in lib) require(lib[i], obj, libs_obj);
return;
}
var lib = libs_obj[lib];
if (lib.callbacks === undefined) lib.callbacks = [];
if (lib.check()) { if (obj.callback) obj.callback(); return; }
lib.callbacks.push(obj);
if (lib.pending) { return; }
lib.pending = true;

lib.pending = false;
var obj;
while (obj = lib.callbacks.pop()) {
obj.count--; if (obj.count == 0) obj.callback();
}
}

}

var script = document.createElement('script');
script.type = 'text/javascript';
script.async = 'async';
script.src = src;

// Based on jQuery jsonp trick
if (callback) {
callback();
}
};
}
}

var deps_count = lib.deps ? lib.deps.length : 0;
if (deps_count < 1) { ready(); return; }
var new_obj = { callback: ready, count: deps_count };

require(lib.deps, new_obj, libs_obj);
};


This function work in IE6+ (and, of course, in other browsers) and written in pure JS. To call this function, use syntax like this:

require(['list', 'of', 'libraries'], function () { alert 'All libs loaded'; }, libs_obj),


where libs_obj is object like this:

{
list: {
check: function() { return list_exist(); },
// function to check whether the required functionality
deps: ['libraries', 'of']
// list of dependencies of current library
// If not, library doesn't have dependencies
},
of: {
check: function() { return of_exist_and_version_is('1.2.3'); },
},
libraries: {
check: funcion() { return libraries_exist() || analog_exist(); },
deps: ['of']
}
}


Callback function are optional - if we don't need it, we can just type false or undefined. Of course, this function must be called after all third-party scripts. Bottom of page is better place to script with this function. Please tell me where I went wrong or give me useful advice.

• Parts of it are very clear, but the callback handling could use some comments or reworking. You have obj which can be a function or an object with a callback property, and libs_obj can have its own callbacks (one or many per library?). In some cases these are combined, and it wasn't clear when or why. Of course, I read it last night and only got a chance to comment on it today. :) May 10 '11 at 1:52
• Thanx. But libs_obj doesn't have a callback for libraries - it just a object that contain info about each library - how to check its availability, path to it and list of dependencies.
– user4126
May 10 '11 at 5:05
• Right, libs is the one with the optional callbacks property. May 10 '11 at 6:00
• I don't really understand how loading libraries asynchronously will reduce HTTP connections or even traffic. Can you clarify? Jul 26 '11 at 11:06
• @EricBréchemier With this library we load needed libs only if they are not loaded later - so, this will reduce traffic and HTTP connections. As you can see in first sentence, this lib created for using on 3rd party websites by webmasters.
– user4126
Sep 27 '11 at 5:05

My 2 cents:

• please use lowercase camelcase ( lib_is_list -> libIsList )
• The first 5 lines seem clumsy
• Checking for an array with typeof 'object' is odd
• Changing the type of a variable/parameter is odd and not recommended, you do this twice
• Dont drop newlines ( for (var i in lib) require(lib[i], obj, libs_obj); )
• You can use lib.callbacks = lib.callbacks || [] instead of if (lib.callbacks === undefined) lib.callbacks = [];
• Why would you assign first callbacks, and then check() whether you should return
• Your handling of obj , count and callbacks is roundabout, the lack of newlines dont help,
• The function name ready() is unfortunate, ready is most commly used for the callback after http requests
• You should consider merging/reworking ready/script_downloaded/download_script
• The src parameter is unfortunate, since it does not contain the source, maybe url ?
• I like defensive programming, but checking for callback seems much, since your code guarantees it

Overal, I have to say this seems over-engineered, I think you are trying to be too smart.