views:

147

answers:

2

I already have code which lazy loads scripts on request. My issue now is waiting to execute certain code until the object becomes available. I can't use a setTimeout() because it does not block execution.

So what is a good way to 'wait' for a load, without locking the browser?

Again, can't use raw setTimeout().

+3  A: 

Assuming you control the contents of your script, you can put some code to execute at the bottom of your lazy loaded script to indicate to the main page that the script has loaded. For example, in your page you can do something like this:

var loadingScripts = 0;
var loadScript = function() {
    // Do what you need to do to load the script...

    loadingScripts++;
}

var loadedScript = function() {
    loadingScripts--;
    if (loadingScripts == 0) {
        // Kick off execution of code that requires the lazy loaded scripts.
    }
}

Then in your script, you'd add this code to the bottom:

loadedScript();

You can spice this example up with an array instead of an integer (to keep track of which specific scripts have loaded). You could also use an object instead to associate particular function calls with the completion of particular scripts. I kept my example simple, but ask if you want me to show how to do extend the code.


Here is how you can use a callback to continue execution of specific code upon loading of a script (again, assuming you control the scripts themselves).

var scriptCallbacks = {}
var loadScript = function(scriptname, callback) {
    // Do what you need to load scriptname

    scriptCallbacks[scriptname] = callback;
}

var loadedScript = function(scriptname) {
    (scriptCallbacks[scriptname])();
}

Then when you want to load a script, you do something like this...

var callback = function() {
    // Write exactly what you want executed once your script is loaded
}

loadScript("MyScript.js", callback);

And again, in your lazy loaded script, just add this code to the bottom to inform your callback to fire:

loadedScript("MyScript.js");
Daniel Lew
The loaded script is not only used for one or two things. They are complete libraries which are called from many different sections of the site as needed. There is not a clean way (that I can think of) to know what source requested the load.
Spot
It's possible to create a lazyloading function which takes another function as a callback, and to fire the callback when the script is loaded. The main point of my example is that you can have the linked script tell you when it's loaded, rather than trying to poll it.
Daniel Lew
It does however completely decimate the ability to use this inline. Thanks for the info.
Spot
What do you mean by "decimate the ability to use this inline"?
Daniel Lew
You won't be able to do it inline, that's the asynchronous nature of the beast. Short of doing a while true loop (which will lock up the browser) you're going to have to split your code out into the "before load" and "after load" blocks, possibly using Daniel's technique.
Dan F
+2  A: 

I'd actually do it differently than Daniel mentioned. All elements fire a load event when they have loaded, and a Javascript file is loaded after it has evaluated the content. So you can set an event handler to continue execution after their available:

var loadScript = function(fileName, callback) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = fileName;

    script.onload = callback;
    script.onreadystatechange = function() {
     if(this.readyState == 'complete') {
      callback();
     }
    };
    head.appendChild(script);
};

And an example usage:

var bar = function() {
    Foo.baz();
};
if(!window.Foo) {
    loadScript('Foo.js',bar);
} else {
    bar();
}
seanmonstar
It is important to note that script.onload doesn't work in some browsers (such as Internet Explorer).
Daniel Lew
However, in IE, it DOES fire an onreadystatechange event, so I could write this better to use onload or onreadystatechange to make it crossbrowser
seanmonstar