Reputation: 2015
I have the following javascript list, each item in this list has a script file url and a callback function, what i want to do is to iterate through this list, load each script, then execute the callback function, and NOT moving to next item unless the current callback is done executing..
var data = {
scripts: [
{
file : 'some-script.js',
callback: function() {
// do some code here
},
},
{
file : 'another-script.js',
callback: function() {
// do some code here
},
},
...
]
};
how can I do this automatically, if Possible ?
Upvotes: 0
Views: 1218
Reputation: 1787
(I'm assuming that you are using JSONP to load your external scripts) The problem that you will face is that these scripts will not load all at the same time.
Below is some code that will call your callback function as soon as the associated script is loaded.
function include_js(url, callback) { // http://www.nczonline.net
var script = document.createElement("script");
script.type = "text/javascript";
if (script.readyState) { //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
//Edit
for (var i = 0; i < data.scripts.length; i++) {
include_js(data.scripts[i].file, data.scripts[i].callback);
}
Upvotes: 2
Reputation: 1074258
It's possible if there's a symbol you can test for in each script, or if each script can execute a function call when it's done loading.
Loading the script is easy, as I'm sure you know:
var script = document.createElement('script');
script.src = /* ... the source path ... */;
document.body.appendChild(script);
(You'll see people appending to head
instead; doesn't matter, and body
is easy to find.)
But the hard part is knowing when it has been downloaded and executed. The only real ways of doing that are by polling to see if a new global symbol defined by the script has been defined, or by having the script actively call you back when it's done loading (a'la JSONP).
Either way, once you've detected the symbol or gotten the callback, you then move on to loading the next script.
Here's a quick-and-dirty sketch of doing it on the basis of finding a global symbol (a property on the window
object):
// The scripts to load
var scriptList = {
scripts: [
{
file : 'some-script.js',
callback: function() {
// do some code here
},
symbol : "someSymbol",
timeout : 30000 // We know this one is slow, give it 30 seconds
},
{
file : 'another-script.js',
callback: function() {
// do some code here
},
symbol : "anotherSymbol"
},
// ...
]
};
// Triggering the load
loadScripts(scriptList);
// Library routines to do the load
function loadScripts(list)
{
var index, timeout;
// Start with the first one (loadNextScript starts with an increment)
index = -1;
loadNextScript();
// This function loads the next script in the list; if there are no
// more, it simply returns
function loadNextScript()
{
var script;
// Are there more?
++index;
if (index < list.length)
{
// Yes, append a `script` element
script = document.createElement('script');
script.src = list.file;
document.body.appendChild(script);
// Determine when to time out
timeout = new Date() + (list[index].timeout || 20000); // Time out in Xms, default 20 seconds
// Start polling
setTimeout(pollForScript, 0); // Async, but almost immediately (4-10ms on most browsers)
}
}
// This function polls to see if the current script has loaded yet by
// checking for a global symbol it defines.
function pollForScript()
{
var result;
// Has it been too long?
if (new Date() > timeout)
{
// Yes
result = "timeout";
}
else
{
// Has the symbol been defined?
if (typeof window[list[index].symbol] !== "undefined")
{
// Yes
result = "loaded";
}
else
{
// Nope, keep waiting
setTimeout(pollForScript, 250); // Check every quarter-second
}
}
// Did we get a result?
if (result)
{
// Yes, do the callback telling it of the result
try {
list[index].callback(result);
}
catch (e) {
}
// Load the next script
loadNextScript();
}
}
}
Upvotes: 1
Reputation: 1745
this is just something quick I wrote up and HAVENT TESTED, but it should do what you are after in a recursive fashion. Hope this helps:
var data = {
scripts: [
{
file : 'some-script.js',
callback: function() {
// do some code here
},
},
{
file : 'another-script.js',
callback: function() {
// do some code here
},
},
...
]
};
$(document).ready(function() {
if(data.scripts.length > 0) {
scriptLoader(0);
}
});
function scriptLoader(i) {
var currScript = data.scripts[i];
$.getScript(currScript.file, function() {
// execute your callback
currScript.callback();
// load next script
if(i < data.scripts.length) {
scriptLoader(i++);
}
});
}
Oh and btw this uses the JQuery javascript framework, just FYI.
Upvotes: 0
Reputation: 5462
Let the callback call your loadTheNextScriptInList
or whatever function. You can do this automatically by adding an anonymous function to the onLoad event. This anonymous function should first call the callback set in the list, and then call your loadTheNextScriptInList
function.
Upvotes: 0