IT Man
IT Man

Reputation: 1036

Loading javascript dynamically - wait for execution?

I'm loading multiple javascript references dynamically with appending script tag to DOM.

I would appreciate your help with explaining script loading behavior.

What i'm assuming is that when i append script element to DOM, script is downloaded and then executed. But when .onload event is fired? As soon as script starts execution or when it finishes execution? If second is true, how to await for script to be executed/initialized (i would like to execute callback that will append additional html with scripts that depends dynamically loaded references )?

To load scripts i use function of below:

function recursiveInclude(scriptPathArray, callback) {
    if (scriptPathArray.length > 0) {
        var scriptPath = scriptPathArray[0];

        // check if script is already loaded if not load
        // this_loadedScriptList is one scope level up variable
        if (this_loadedScriptList.indexOf(scriptPath) > 0 == false) {
            var body        = document.getElementsByTagName('body')[0];
            var scriptElement       = document.createElement('script');
            scriptElement.type  = 'text/javascript';
            scriptElement.src       = scriptPath;

            // first script from the array will loaded as soon as body.appendChild function will be called
            // when script loads 'onload' event will fire next script loading
            // to this work properly first script from scriptPathArray has to be removed:
            scriptPathArray.shift();


            // if there are any other scripts to load, load them sequentially
            if (scriptPathArray.length > 0) {
                // then bind the event to the callback function
                // there are several events for cross browser compatibility
                // script.onreadystatechange = callback;

                scriptElement.onload = recursiveInclude(scriptPathArray, callback);                 
            } else {
                // if no other scripts to load - fire base callback;
                scriptElement.onload = callback;
            }    

            // fire the loading
            body.appendChild(scriptElement);

            // add script to loaded array.
            this_loadedScriptList.push(scriptPath);
        }           
    }

}

Upvotes: 4

Views: 10450

Answers (2)

Pinke Helga
Pinke Helga

Reputation: 6692

JavaScript is neither threaded nor event-interrupted. The hole script is executed before anything else can happen. Events are captured until the browser gets back the control. So onload or any other event can only be fired before or after the script execution is done. Actually onload is fired after the execution.

There is an event beforescriptexecute still supported by firefox, however, it has been remove from HTML5.1 specs.

You can try it out yourself:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
    <script>

      console.log('base script start');

      var script=document.createElement('script');
      script.onload = function() { console.log('onload fired'); }

      // MDN says:
      // This event was a proposal in an early version of the specification. Do not rely on it.
      // 
      script.addEventListener('beforescriptexecute', function () { console.log('beforescriptexecute fired'); });

      script.src = 'external.js';
      document.head.appendChild(script);

      console.log('waiting 3 seconds');
      timebase = Date.now();
      while((Date.now() - timebase) < 3000)
        ;
      console.log("base script end");
    </script>

</body>
</html>

external.js:

console.log('external start... waiting 3 seconds');
timeext = Date.now();
while((Date.now() - timeext) < 3000)
  ;

console.log('external end');

base script start
waiting 3 seconds
base script end
beforescriptexecute fired
external start... waiting 3 seconds
external end
onload fired

MDN - beforescriptexecute

Upvotes: 2

Yaser
Yaser

Reputation: 5719

there is a big issue you must know about. Doing that implies that you remotely load the code. Modern web browsers will load the file and keep executing your current script because they load everything asynchronously to improve performance. (This applies to both the jQuery method and the manual dynamic script loading method.)

It means that if you use these tricks directly, you won't be able to use your newly loaded code the next line after you asked it to be loaded, because it will be still loading.

Practically all you can do is to use an event to run a callback function when the script is loaded.

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

    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}

Then write your code like this:

var myCode = function() {
  ...
};

At last you can run it:

loadScript("the-remote-script.js", myCode);

Upvotes: 4

Related Questions