1

For my website I wanted to use conditional javascript loading when certain elements are detected. At first I only created a new script element and append it to the head. When I do this the commands following that statement would always fail because the browser is still loading the javascript file and the function is not ready yet. $("element").something is not a function

A second problem was when another part of my script wanted to include a script that was already requested before. I could not safely assume the script would always still be loading or was already loaded upon that point.

So I wrote a script that could execute callbacks when a script/scripts is/are loaded. This is how my function looks like now:

/* LOADING LIST */
var loading = new Array();

function include(script, callback) {
    if (script instanceof Array) {
        /* load an array of scripts */
        if (script.length > 1) {
            var top = script.shift();
            include(top, function() {
                include(script, callback);
            });
        } else
            include(script[0], callback);
    } else {
        var source = base_url + script;
        var type = /[^.]+$/.exec(script);

        if (type == "js") {
            if ($('script[src="' + source + '"]').length == 0) {
                /* first time script is requested */
                loading[script] = true;

                var e = document.createElement('script');
                e.src = source;
                e.type = "text/javascript";
                e.onload = function() {
                    delete loading[script];
                    if (callback !== undefined) {
                        callback();
                    }
                };
                document.getElementsByTagName("head")[0].appendChild(e);
            }
            else if(script in loading) {
                /* script is being loaded */
                var e = $('script[src="' + source + '"]')[0];
                var old = e.onload;
                e.onload = function() {
                    old();
                    callback();
                };
            }
            else {
                /* script is loaded */
                callback();
            }
        }
        else if (type == "css") {
            /* no need to wait for stylesheets */
            if ($('link[href="' + source + '"]').length == 0) {
                var e = document.createElement('link');
                e.rel = 'stylesheet';
                e.type = 'text/css';
                e.href = source;
                document.getElementsByTagName("head")[0].appendChild(e);
            }
            if (callback !== undefined) {
                callback();
            }
        }
    }
}

It supports things like this:

if($('.wysiwyg').length>0) {
    include(['javascript/ckeditor/ckeditor.js','javascript/ckeditor/adapters/jquery.js'], function() {
        $(".wysiwyg").ckeditor();
    }
}

This will only execute the callback when all the mentioned scripts are loaded.

I do not know very much about javascript and I was wondering if this script could become shorter and/or more efficient.

1
  • First of all you can could (and should) place your JavaScript at the end of your html document, that way all your DOM elements will be loaded and ready to access. Secondly, why are you going through all the trouble of conditionally loading scripts? There is no need to do this for performance reasons unless your scripts are really huge. Just load them and they'll be cached by the browser ready for any other page that needs them. Commented Jul 12, 2011 at 9:06

1 Answer 1

1

you should use $.getScript() from jQuery. It does what you are doing. And you can also make it load synchronous with $.ajaxSetup({async: false});

for example

$.ajaxSetup({async: false});
$.getScript('myClass.js');
imFromMyClass();

I use a function like:

function require(module) {
    $.ajaxSetup({async: false, cache: true});

    if (window['matchExtension'] === undefined) {
        window['matchExtension'] = function(filename, extensions) {
            return (getFileExtension(filename).match(new RegExp("(" + extensions + ")", "ig")));
        }
    }

    if (typeof module == 'string') {
        var tmp = "";
        if (matchExtension(module, "htm*") || matchExtension(module, "txt")) {
            tmp = $.get(module).responseText;
            return tmp;
        } else if (matchExtension(module, "css")) {
            var obj = $.get(module);
            if (obj.status == 404) return '';

            tmp = obj.responseText;
            var el = document.createElement('style');
            el.type = 'text/css';
            el.media = 'screen';
            document.getElementsByTagName('head')[0].appendChild(el);
            if(el.styleSheet) el.styleSheet.cssText = tmp;// IE method
            else el.appendChild(document.createTextNode(tmp));// others
        } else if (module.EndsWith("/")) {
            return $.get(module).responseText; // directory listing
        } else {
            $.getScript(module);
        }
    } else {
        $.ajaxSetup({async: false, cache:true});
        for (var i =0, len = module.length; i < len; i++) $.getScript(module[i]);
    }
    return true;
}

var content = require('someFile.html');
require('someStyle.css');
require('someClass.js');
require(['class1.js', 'class2.js', 'class3.js']);

one other improvement you can do when loading an array of javascript files is to serve the list to a server script that concatenates them all in the same response

Sign up to request clarification or add additional context in comments.

2 Comments

Would require(['class1.js', 'class2.js', 'class3.js']); not be more elegant?
I tried getScript but that gave problems when the same javascript was requested more than once.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.