4

today I've been working on loading dynamic javascript code (files). The solution I use is :

function loadScript(scriptUrl) {
        var head = document.getElementsByTagName("head")[0];
        var script = document.createElement('script');
        script.id = 'uploadScript';
        script.type = 'text/javascript';
        script.src = scriptUrl;
        head.appendChild(script);
    }

the problem with this is that I don't know how to make sure WHEN the script contents are executed. Since the script contains classes (well JS classes), I wrote down a function that is called through setTimeout and checks if those objects are defined. This is not flexible as it is not automatical. So? Are there ways to load those scripts and have a reliable notification on when they have been executed?

RC.
  • 27,409
  • 9
  • 73
  • 93
gotch4
  • 13,093
  • 29
  • 107
  • 170
  • 1
    Dupicate of http://stackoverflow.com/questions/3125897/loading-scripts-dynamically/3125918#3125918 – tcooc Aug 19 '10 at 15:05
  • 1
    Why not take a look at an existing solution like LabJS? http://labjs.com/ – Pointy Aug 19 '10 at 15:06
  • no offense, but this reeks of a bad design decision. – Fosco Aug 19 '10 at 15:08
  • LabJs fails with jQuery, I tried it this morning... – gotch4 Aug 19 '10 at 15:09
  • possible duplicate of [script onload/onerror with IE(for lazy loading) problems](http://stackoverflow.com/questions/3483919/script-onload-onerror-with-iefor-lazy-loading-problems) – Marcel Korpel Aug 19 '10 at 15:42
  • And if I'm not mistaken, the script is executed just *before* the load event occurs. But you can always test within `onload`, e.g. `if ('jQuery' in window)`. No IE knowledge on this, though. – Marcel Korpel Aug 19 '10 at 15:48

3 Answers3

3

You can use jquery's getScript and pass a callback function.

$.getScript("test.js", function(){
   alert("Script loaded and executed.");
 });

See: jquery.

Topera
  • 12,223
  • 15
  • 67
  • 104
  • eh... unfortunately this has to load jQuery itself uhuhuhu – gotch4 Aug 19 '10 at 15:06
  • 1
    +1. This way you can support dependency and load them in order by nesting the getScript calls in the callback functions. – Fosco Aug 19 '10 at 15:06
  • You can check out the jQuery source code, it can be easily implemented using plain JavaScript, see: http://gist.github.com/538106 – tszming Aug 19 '10 at 15:20
  • Note that as per [jQuery docs](http://api.jquery.com/jQuery.getScript/) currently : _The callback is fired once the script has been loaded but **not necessarily executed.**_ i.e. It doesn't guarantees execution of script. – Ankit Feb 19 '16 at 09:03
2

The easiest way short of a JS library is to make an XMLHttpRequest and eval() the return. Your "onload" would be when the data is returned, and "oninit" would be right after you've eval'd.

EDIT: If you want to sequence this, you can create an AssetLoader that takes an array of scripts and won't eval() a script until the one preceding it has been fetched and initialized.

EDIT 2: You can also use the script.onload stuff in the post referenced in the comments. The eval method has a slight advantage in that you can separate and control the load and execution portions of the script import.

EDIT 3: Here's an example. Consider a file called foo.js that contains the following:


function foo () {
    alert('bar');
}

Then execute the following from another page in your browser:



function initScript (scriptString) {
    window.eval(scriptString);
}

function getScript (url, loadCallback, initCallback, callbackScope) {

    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onreadystatechange = function (e) {

        if (req.readyState == 4) {
            if (loadCallback) loadCallback.apply(callbackScope);
            initScript.call(null, req.responseText);
            if (initCallback) initCallback.apply(callbackScope);
        }

    }

    req.send();

}

function fooScriptLoaded () {
    alert('script loaded');
}

function fooScriptInitialized () {
    alert('script initialized');
    foo();
}

window.onload = function () {
    getScript('foo.js', fooScriptLoaded, fooScriptInitialized, null);
}

You will see the alerts "script loaded", "script initialized", and "bar". Obviously the implementation of XMLHttpRequest here isn't complete and there are all sorts of things you can do for whatever scope you want to execute the script in, but this is the core of it.

sevenflow
  • 767
  • 1
  • 6
  • 21
  • After eval() the script has been initialized. You can throw a try-catch block around it to see if any errors prevent the script from initializing. – sevenflow Aug 19 '10 at 15:13
-2

You could use a counter variable, and a kind of callback:

var scriptsToLoad = 10;
var loadedScripts = 0;
//...
function increaseLoadCount() {
loadedScripts++;
if(loadedScripts == scriptsToLoad) {
alert("start here");
}
}

//script1-10.js
increaseLoadCount();

Maybe a bit nicer than with a timeout..

Fabian Fritz
  • 390
  • 3
  • 14