Reputation: 1036
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
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
Upvotes: 2
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