How to include multiple js files using jQuery $.getScript() method
Solution 1:
The answer is
You can use promises with getScript()
and wait until all the scripts are loaded, something like:
$.when(
$.getScript( "/mypath/myscript1.js" ),
$.getScript( "/mypath/myscript2.js" ),
$.getScript( "/mypath/myscript3.js" ),
$.Deferred(function( deferred ){
$( deferred.resolve );
})
).done(function(){
//place your code here, the scripts are all loaded
});
FIDDLE
ANOTHER FIDDLE
In the above code, adding a Deferred and resolving it inside $()
is like placing any other function inside a jQuery call, like $(func)
, it's the same as
$(function() { func(); });
i.e. it waits for the DOM to be ready, so in the above example $.when
waits for all the scripts to be loaded and for the DOM to be ready because of the $.Deferred
call which resolves in the DOM ready callback.
For more generic use, a handy function
A utility function that accepts any array of scripts could be created like this :
$.getMultiScripts = function(arr, path) {
var _arr = $.map(arr, function(scr) {
return $.getScript( (path||"") + scr );
});
_arr.push($.Deferred(function( deferred ){
$( deferred.resolve );
}));
return $.when.apply($, _arr);
}
which can be used like this
var script_arr = [
'myscript1.js',
'myscript2.js',
'myscript3.js'
];
$.getMultiScripts(script_arr, '/mypath/').done(function() {
// all scripts loaded
});
where the path will be prepended to all scripts, and is also optional, meaning that if the array contain the full URL's one could also do this, and leave out the path all together
$.getMultiScripts(script_arr).done(function() { ...
Arguments, errors etc.
As an aside, note that the done
callback will contain a number of arguments matching the passed in scripts, each argument representing an array containing the response
$.getMultiScripts(script_arr).done(function(response1, response2, response3) { ...
where each array will contain something like [content_of_file_loaded, status, xhr_object]
.
We generally don't need to access those arguments as the scripts will be loaded automatically anyway, and most of the time the done
callback is all we're really after to know that all scripts have been loaded, I'm just adding it for completeness, and for the rare occasions when the actual text from the loaded file needs to be accessed, or when one needs access to each XHR object or something similar.
Also, if any of the scripts fail to load, the fail handler will be called, and subsequent scripts will not be loaded
$.getMultiScripts(script_arr).done(function() {
// all done
}).fail(function(error) {
// one or more scripts failed to load
}).always(function() {
// always called, both on success and error
});
Solution 2:
I implemented a simple function to load multiple scripts in parallel:
Function
function getScripts(scripts, callback) {
var progress = 0;
scripts.forEach(function(script) {
$.getScript(script, function () {
if (++progress == scripts.length) callback();
});
});
}
Usage
getScripts(["script1.js", "script2.js"], function () {
// do something...
});
Solution 3:
Load the following up needed script in the callback of the previous one like:
$.getScript('scripta.js', function()
{
$.getScript('scriptb.js', function()
{
// run script that depends on scripta.js and scriptb.js
});
});
Solution 4:
Sometimes it is necessary to load scripts in a specific order. For example jQuery must be loaded before jQuery UI. Most examples on this page load scripts in parallel (asynchronously) which means order of execution is not guaranteed. Without ordering, script y
that depends on x
could break if both are successfully loaded but in wrong order.
I propose a hybrid approach which allows sequential loading of dependent scripts + optional parallel loading + deferred objects:
/*
* loads scripts one-by-one using recursion
* returns jQuery.Deferred
*/
function loadScripts(scripts) {
var deferred = jQuery.Deferred();
function loadScript(i) {
if (i < scripts.length) {
jQuery.ajax({
url: scripts[i],
dataType: "script",
cache: true,
success: function() {
loadScript(i + 1);
}
});
} else {
deferred.resolve();
}
}
loadScript(0);
return deferred;
}
/*
* example using serial and parallel download together
*/
// queue #1 - jquery ui and jquery ui i18n files
var d1 = loadScripts([
"https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js",
"https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/i18n/jquery-ui-i18n.min.js"
]).done(function() {
jQuery("#datepicker1").datepicker(jQuery.datepicker.regional.fr);
});
// queue #2 - jquery cycle2 plugin and tile effect plugin
var d2 = loadScripts([
"https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/jquery.cycle2.min.js",
"https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/plugin/jquery.cycle2.tile.min.js"
]).done(function() {
jQuery("#slideshow1").cycle({
fx: "tileBlind",
log: false
});
});
// trigger a callback when all queues are complete
jQuery.when(d1, d2).done(function() {
console.log("All scripts loaded");
});
@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/blitzer/jquery-ui.min.css");
#slideshow1 {
position: relative;
z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<p><input id="datepicker1"></p>
<div id="slideshow1">
<img src="https://dummyimage.com/300x100/FC0/000">
<img src="https://dummyimage.com/300x100/0CF/000">
<img src="https://dummyimage.com/300x100/CF0/000">
</div>
The scripts in both queues will download in parallel, however, the scripts in each queue will download in sequence, ensuring ordered execution. Waterfall chart: