Dynamically load a JavaScript file

Adam picture Adam · Aug 21, 2008 · Viewed 159.9k times · Source

How can you reliably and dynamically load a JavaScript file? This will can be used to implement a module or component that when 'initialized' the component will dynamically load all needed JavaScript library scripts on demand.

The client that uses the component isn't required to load all the library script files (and manually insert <script> tags into their web page) that implement this component - just the 'main' component script file.

How do mainstream JavaScript libraries accomplish this (Prototype, jQuery, etc)? Do these tools merge multiple JavaScript files into a single redistributable 'build' version of a script file? Or do they do any dynamic loading of ancillary 'library' scripts?

An addition to this question: is there a way to handle the event after a dynamically included JavaScript file is loaded? Prototype has document.observe for document-wide events. Example:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

What are the available events for a script element?

Answer

aemkei picture aemkei · Oct 28, 2008

You may write dynamic script tags (using Prototype):

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

The problem here is that we do not know when the external script file is fully loaded.

We often want our dependant code on the very next line and like to write something like:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

There is a smart way to inject script dependencies without the need of callbacks. You simply have to pull the script via a synchronous AJAX request and eval the script on global level.

If you use Prototype the Script.load method looks like this:

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};