If injecting multiple script tags in the head like this with mix of local and remote script files a situation may arise where the local scripts that are dependent on external scripts (such as loading jQuery from googleapis) will have errors because the external scripts may not be loaded before the local ones are.
So something like this would have a problem: ("jQuery is not defined" in jquery.some-plugin.js).
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js";
head.appendChild(script);
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "/jquery.some-plugin.js";
head.appendChild(script);
Of course this situation is what the .onload() is for, but if multiple scripts are being loaded that can be cumbersome.
As a resolution to this situation, I put together this function that will keep a queue of scripts to be loaded, loading each subsequent item after the previous finishes, and returns a Promise that resolves when the script (or the last script in the queue if no parameter) is done loading.
load_script = function(src) {
// Initialize scripts queue
if( load_script.scripts === undefined ) {
load_script.scripts = [];
load_script.index = -1;
load_script.loading = false;
load_script.next = function() {
if( load_script.loading ) return;
// Load the next queue item
load_script.loading = true;
var item = load_script.scripts[++load_script.index];
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = item.src;
// When complete, start next item in queue and resolve this item's promise
script.onload = () => {
load_script.loading = false;
if( load_script.index < load_script.scripts.length - 1 ) load_script.next();
item.resolve();
};
head.appendChild(script);
};
};
// Adding a script to the queue
if( src ) {
// Check if already added
for(var i=0; i < load_script.scripts.length; i++) {
if( load_script.scripts[i].src == src ) return load_script.scripts[i].promise;
}
// Add to the queue
var item = { src: src };
item.promise = new Promise(resolve => {item.resolve = resolve;});
load_script.scripts.push(item);
load_script.next();
}
// Return the promise of the last queue item
return load_script.scripts[ load_script.scripts.length - 1 ].promise;
};
With this adding scripts in order ensuring the previous are done before staring the next can be done like...
["https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js",
"/jquery.some-plugin.js",
"/dependant-on-plugin.js",
].forEach(load_script);
Or load the script and use the return Promise to do work when it's complete...
load_script("some-script.js")
.then(function() {
/* some-script.js is done loading */
});