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
    // instead of function
    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);
    var lib = libs_obj[lib];
    if (lib.callbacks === undefined) lib.callbacks = [];
    if (lib.check()) { if (obj.callback) obj.callback(); return; }
    if (lib.pending) { return; }
    lib.pending = true;

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

        download_script(lib.link, script_downloaded);

    function download_script(src, callback) {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.async = 'async';
        script.src = src;

        // Based on jQuery jsonp trick
        if (callback) {
            script.onload = script.onreadystatechange = function() {
                if (!script.readyState || /loaded|complete/.test(script.readyState)) {
                    script.onload = script.onreadystatechange = null;

    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
        link: 'js/list_js_file.js',
        // link to script
        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'); },
        link: 'js/another_file.js',
    libraries: {
        check: funcion() { return libraries_exist() || analog_exist(); },
        link: 'http://www.example.com/js/libraries.js',
        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.

  • \$\begingroup\$ 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. :) \$\endgroup\$ May 10, 2011 at 1:52
  • \$\begingroup\$ 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. \$\endgroup\$
    – user4126
    May 10, 2011 at 5:05
  • \$\begingroup\$ Right, libs is the one with the optional callbacks property. \$\endgroup\$ May 10, 2011 at 6:00
  • 4
    \$\begingroup\$ I don't really understand how loading libraries asynchronously will reduce HTTP connections or even traffic. Can you clarify? \$\endgroup\$ Jul 26, 2011 at 11:06
  • \$\begingroup\$ @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. \$\endgroup\$
    – user4126
    Sep 27, 2011 at 5:05

1 Answer 1


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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.