First of all, I would split you problem into 3 parts:
- Loading a js-file asynchronously, and calling a callback-function
- Loading several js-files an once asynchronously
- Using an onload-Handler, which triggers everything
These are 3 independent parts, which might be reused for other purposes, if seperated correctly.
1. Loading a js-file asynchronously
You're using 2 strings to specify a file to be loaded. But instead of writing
["file.js", "cbFunction"]
you can as well also pass the actual function:
["file.js", cbFunction]
This not only ensures that the function actually exists, it also gives you the opportunity to use anonymous functions:
["file.js", function(){ alert("loaded!"); } ]
However, speaking of segregation of responsibilities, you should write a function on its own, without the need of an Array anymore:
function loadScript(path, scriptLoadedCallback){
var element=document.createElement('script'); //generate <script>-tag
element.setAttribute("type","text/javascript");
element.setAttribute("src", path);
if(typeof(scriptLoadedCallback) == 'function'){ //makes the callback-function optional
element.onload = function() {
return scriptLoadedCallback(true, path); //true = successfull; the path is needed later
};
element.onerror = function() { //you might also call the cb on error
this.parentNode.removeChild(this); //remove faulty node from DOM
return scriptLoadedCallback(false, path); //false = error; the path is needed later
};
}
document.head.appendChild(fileref); //insert the node in DOM (end of <head>), and load the script
}
This function looks much clearer, and you can see at first glance what it is doing.
Note that I checked the existence of the callback before I append an onload-attribute. This is a bit more efficient than your code, which always calls the onload
-Handler and then does nothing.
You might also want to add the onerror
-method, otherwise you will never get notified if the loading failed (This usually happens if the js-file doesn't exist).
If you only have to load a single script, you can call this function directly. No need to generate useless Arrays.
2. Loading several js-files an once
If you only want to load several files, and calling a callback after each file, this is an easy task, using your original array (with functions instead of strings):
var filesToLoad = [
["file1.js", cbFunctionToCall],
["file2.js"]
];
for(var i=0; i<filesToLoad.length; i++){ //I prefer a for-loop because its more readable
loadScript(filesToLoad[i][0], filesToLoad[i][1];
}
And that's all.
However, if you want to have one callback-function which is called after all files have been loaded, this gets a bit tricky. You don't know which file is the last one, and which file should trigger the actual callback-function.
function loadScriptArray(contentArray, contentLoadedCallback){
var contentQuantity = contentArray.length; //Number of Files that needs to be loaded
var contentCompleted = 0; //Number of Files, that have already been loaded
var returnParamList = {}; //List with return-Parameters
if(contentQuantity == 0){ //We don't have anything to load
return contentLoadedCallback({});
}
for (var i = 0; i < contentQuantity; i++) {
loadScript(contentArray[i], function(success, path){ //This anonymous function is called everytime a script is finished
//The only way to know which script finished, is to pass the path as an parameter
returnParamList[ identifier ] = returnParam; //store the returnValue (true=success, false=error)
contentCompleted++;
if(contentCompleted == contentQuantity){ //this was the last file
if(typeof contentLoadedCallback== 'function'){
contentLoadedCallback(returnParamList);
}
}
});
}
}
This is how the function is being called:
loadScriptArray(["file1.js", "file2.js"], function(returnParamList){
alert("All Scripts finished. \n"+
"File1: "+returnParamList["file1.js"]+"\n"+
"File2: "+returnParamList["file2.js"]);
});
This function loads 2 files simultaneously, and calls the callback after the last one has been loaded. Afterwards it prints which files have been loaded successfully, and which loading-operation failed.
This only works, if the initial loadScript()
-Function always calls the callback-Function - both if it succeeded or failed. And to report the success back to the caller, the callback-function also needs the filePath as an parameter.
Another advantage is, that you can extend this function to also load other files like images, json, xml and so on.
3. Trigger loading with onload
You code looks fine here, with only one very bad issue: Use brackets, they won't kill you.
There's absolutely no reason to omit brackets, it's just a possible source for annoying errors, which are very hard to be found.
onTypeadheadLoaded
. There are many more elegant ways to do this.typeahead
requires jQuery yes? why not usegetScript
\$\endgroup\$entry[1] != "" && typeof window[entry[1]] != "undefined"
\$\endgroup\$async
attribute, can I specify a callback somehow? \$\endgroup\$