How to include multiple js files using jQuery $.getScript() method

JavascriptJqueryHtmlPromise

Javascript Problem Overview


I am trying to dynamically include javascript files into my js file. I did some research about it and find jQuery $.getScript() method would be a desired way to go.

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // script is now loaded and executed.
    // put your dependent JS here.
    // what if the JS code is dependent on multiple JS files? 
});

But I am wondering whether this method can load multiple scripts at one time? Why I am asking this is because sometimes my javascript file is depending on more than one js files.

Thank you in advance.

Javascript Solutions


Solution 1 - Javascript

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 - Javascript

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 - Javascript

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 - Javascript

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:

waterfall chart of scripts

Solution 5 - Javascript

Use yepnope.js or Modernizr (which includes yepnope.js as Modernizr.load).

UPDATE

Just to follow up, here's a good equivalent of what you currently have using yepnope, showing dependencies on multiple scripts:

yepnope({
  load: ['script1.js', 'script2.js', 'script3.js'],
  complete: function () {
      // all the scripts have loaded, do whatever you want here
  }
});

Solution 6 - Javascript

I ran into a number of issues with multi script loading inculding one issue with (at least in Chrome) same domain hot loading of scripts not actually running after being successfully loaded by Ajax where as Cross Domain works perfectly fine! :(

The selected answer to original question does not work reliably.

After many many iterations here is my final answer to getScript(s) and loading asynchronously multiple scripts in a specific strict order with per script loaded callback option and overall callback on completion, Tested in jQuery 2.1+ and modern versions of Chrome, Firefox plus the forsaken Internet Explorer.

My test case was loading files for a THREE.JS webGL render then starting the render script when THREE global became available using an interval check passed to an anonymous function call to onComplete.

The Prototype function ( getScripts )

function getScripts( scripts, onScript, onComplete )
{
	this.async = true;
	this.cache = false;
	this.data = null;
	this.complete = function () { $.scriptHandler.loaded(); };
	this.scripts = scripts;
	this.onScript = onScript;
	this.onComplete = onComplete;
    this.total = scripts.length;
    this.progress = 0;
};

getScripts.prototype.fetch = function() {
	$.scriptHandler = this;
	var src = this.scripts[ this.progress ];
	console.log('%cFetching %s','color:#ffbc2e;', src);
	
	$.ajax({
		crossDomain:true,
		async:this.async,
		cache:this.cache,
		type:'GET',
		url: src,
		data:this.data,
		statusCode: {
			200: this.complete
		},
		dataType:'script'
	});
};

getScripts.prototype.loaded = function () {
	this.progress++;
	if( this.progress >= this.total ) {
		if(this.onComplete) this.onComplete();
	} else {
		this.fetch();
	};
	if(this.onScript) this.onScript();
};

How to use

var scripts = new getScripts(
    ['script1.js','script2.js','script.js'],
    function() {
        /* Optional - Executed each time a script has loaded (Use for Progress updates?) */
    },
    function () {
        /* Optional - Executed when the entire list of scripts has been loaded */
    }
);
scripts.fetch();

The function is as it is for I found using Deferred ( Deprecated now? ), When, Success & Complete in my trials to NOT be 100% reliable!?, Hence this function and use of statusCode for example.

You may want to add in error/fail handling behaviour if you wish.

Solution 7 - Javascript

You could make use of the $.when-method by trying the following function:

function loadScripts(scripts) {
  scripts.forEach(function (item, i) {
    item = $.getScript(item);
  });
  return $.when.apply($, scripts);
}

This function would be used like this:

loadScripts(['path/to/script-a.js', 'path/to/script-b.js']).done(function (respA, respB) {
    // both scripts are loaded; do something funny
});

That's the way to use Promises and have a minimum of overhead.

Solution 8 - Javascript

Great answer, adeneo.

It took me a little while to figure out how to make your answer more generic (so that I could load an array of code-defined scripts). Callback gets called when all scripts have loaded and executed. Here is my solution:

    function loadMultipleScripts(scripts, callback){
        var array = [];

        scripts.forEach(function(script){
            array.push($.getScript( script ))
        });

        array.push($.Deferred(function( deferred ){
                    $( deferred.resolve );
                }));

        $.when.apply($, array).done(function(){
                if (callback){
                    callback();
                }
            });
    }

Solution 9 - Javascript

Append scripts with async=false

Here's a different, but super simple approach. To load multiple scripts you can simply append them to body.

  • Loads them asynchronously, because that's how browsers optimize the page loading
  • Executes scripts in order, because that's how browsers parse the HTML tags
  • No need for callback, because scripts are executed in order. Simply add another script, and it will be executed after the other scripts

More info here: https://www.html5rocks.com/en/tutorials/speed/script-loading/

var scriptsToLoad = [
   "script1.js", 
   "script2.js",
   "script3.js",
]; 
    
scriptsToLoad.forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.body.appendChild(script);
});

Solution 10 - Javascript

Here is answer using Maciej Sawicki's one and implementing Promise as callback:

function loadScripts(urls, path) {
    return new Promise(function(resolve) {
        urls.forEach(function(src, i) {

            let script = document.createElement('script');        
            script.type = 'text/javascript';
            script.src = (path || "") + src;
            script.async = false;

            // If last script, bind the callback event to resolve
            if(i == urls.length-1) {                    
                // Multiple binding for browser compatibility
                script.onreadystatechange = resolve;
                script.onload = resolve;
            }

            // Fire the loading
            document.body.appendChild(script);
        });
    });
}

Use:

let JSDependencies = ["jquery.js",
                      "LibraryNeedingJquery.js",
                      "ParametersNeedingLibrary.js"];

loadScripts(JSDependencies,'JavaScript/').then(taskNeedingParameters);

All Javascript files are downloaded as soon as possible and executed in the given order. Then taskNeedingParameters is called.

Solution 11 - Javascript

What you are looking for is an AMD compliant loader (like require.js).

http://requirejs.org/

http://requirejs.org/docs/whyamd.html

There are many good open source ones if you look it up. Basically this allows you to define a module of code, and if it is dependent on other modules of code, it will wait until those modules have finished downloading before proceeding to run. This way you can load 10 modules asynchronously and there should be no problems even if one depends on a few of the others to run.

Solution 12 - Javascript

This function will make sure that a file is loaded after the dependency file is loaded completely. You just need to provide the files in a sequence keeping in mind the dependencies on other files.

function loadFiles(files, fn) {
    if (!files.length) {
        files = [];
    }
    var head = document.head || document.getElementsByTagName('head')[0];

    function loadFile(index) {
        if (files.length > index) {
            var fileref = document.createElement('script');
            fileref.setAttribute("type", "text/javascript");
            fileref.setAttribute("src", files[index]);
            head.appendChild(fileref);
            index = index + 1;
            // Used to call a callback function
            fileref.onload = function () {
                loadFile(index);
            }
        } else if(fn){
            fn();
        }
    }
    loadFile(0);
}

Solution 13 - Javascript

This works for me:

function getScripts(scripts) {
    var prArr = [];
    scripts.forEach(function(script) { 
        (function(script){
            prArr .push(new Promise(function(resolve){
                $.getScript(script, function () {
                    resolve();
                });
            }));
        })(script);
    });
    return Promise.all(prArr, function(){
        return true;
    });
}

And use it:

var jsarr = ['script1.js','script2.js'];
getScripts(jsarr).then(function(){
...
});

Solution 14 - Javascript

Shorter version of Andrew Marc Newton's comprehensive answer above. This one does not check the status code for success, which you should do to avoid undefined UI behaviour.

This one was for an annoying system where I could guarantee jQuery but no other includes, so I wanted a technique short enough to not be farmed off into an external script if forced into it. (You could make it even shorter by passing the index 0 to the first "recursive" call but force of style habits made me add the sugar).

I'm also assigning the dependency list to a module name, so this block can be included anywhere you need "module1" and the scripts and dependent initialization will only be included/run once (you can log index in the callback and see a single ordered set of AJAX requests runnning)

if(typeof(__loaders) == 'undefined') __loaders = {};

if(typeof(__loaders.module1) == 'undefined')
{
	__loaders.module1 = false;
	
	var dependencies = [];
		
	dependencies.push('/scripts/loadmefirst.js');
	dependencies.push('/scripts/loadmenext.js');
	dependencies.push('/scripts/loadmelast.js');

	var getScriptChain	= function(chain, index)		
	{
		if(typeof(index) == 'undefined')
			index = 0;
			
		$.getScript(chain[index], 
			function()
			{
				if(index == chain.length - 1)
				{
					__loaders.module1 = true;
			
					/* !!!
						Do your initialization of dependent stuff here 
					!!! */
				}
				else 
					getScriptChain(chain, index + 1);
			}
		);
	};
	
	getScriptChain(dependencies);		
}

Solution 15 - Javascript

There's a plugin out there that extends jQuery's getScript method. Allows for asynchronous and synchronous loading and uses jQuery's caching mechanism. Full disclosure, I wrote this. Please feel free to contribute if you find a better method.

https://github.com/hudsonfoo/jquery-getscripts

Solution 16 - Javascript

Loads n scripts one by one (useful if for example 2nd file needs the 1st one):

(function self(a,cb,i){
	i = i || 0;	
	cb = cb || function(){};	
	if(i==a.length)return cb();
	$.getScript(a[i++],self.bind(0,a,cb,i));					
})(['list','of','script','urls'],function(){console.log('done')});

Solution 17 - Javascript

based on answer from @adeneo above: Combining both loading of css and js files

any suggestions for improvements ??

// Usage
//$.getMultiResources(['script-1.js','style-1.css'], 'assets/somePath/')
//  .done(function () {})
//  .fail(function (error) {})
//  .always(function () {});

(function ($) {
  $.getMultiResources = function (arr, pathOptional, cache) {
    cache = (typeof cache === 'undefined') ? true : cache;
    var _arr = $.map(arr, function (src) {
      var srcpath = (pathOptional || '') + src;
      if (/.css$/i.test(srcpath)) {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'text',
          cache: cache,
          success: function () {
            $('<link>', {
              rel: 'stylesheet',
              type: 'text/css',
              'href': srcpath
            }).appendTo('head');
          }
        });

      } else {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'script',
          cache: cache
        });
      }
    });
    //
    _arr.push($.Deferred(function (deferred) {
      $(deferred.resolve);
    }));
    //
    return $.when.apply($, _arr);
  };
})(jQuery);

Solution 18 - Javascript

You can give this a try using recursion. This will download them in sync, one after another until it completes downloading the whole list.

var queue = ['url/links/go/here'];

ProcessScripts(function() { // All done do what ever you want

}, 0);

function ProcessScripts(cb, index) {
    getScript(queue[index], function() {
        index++;
        if (index === queue.length) { // Reached the end
            cb();
        } else {
            return ProcessScripts(cb, index);
        }
    });
}

function getScript(script, callback) {
    $.getScript(script, function() {
        callback();
    });
}

Solution 19 - Javascript

I have improved @adeneo script so it will load all scripts in the specified order. It doesn't do chain loading, so it's very fast, but if you want even faster, change the 50 ms wait time.

$.getMultiScripts = function(arr, path) {

    function executeInOrder(scr, code, resolve) {
        // if its the first script that should be executed
        if (scr == arr[0]) {
            arr.shift();
            eval(code);
            resolve();
            console.log('executed', scr);
        } else {
            // waiting
            setTimeout(function(){
                executeInOrder(scr, code, resolve);
            }, 50);
        }
    }

    var _arr = $.map(arr, function(scr) {

        return new Promise((resolve) => {
            jQuery.ajax({
                type: "GET",
                url: (path || '') + scr,
                dataType: "text",
                success: function(code) {
                    console.log('loaded  ', scr);
                    executeInOrder(scr, code, resolve);
                },
                cache: true
            });
        });

    });
        
    _arr.push($.Deferred(function( deferred ){
        $( deferred.resolve );
    }));
        
    return $.when.apply($, _arr);
}

Usage is the same:

var script_arr = [
    'myscript1.js', 
    'myscript2.js', 
    'myscript3.js'
];

$.getMultiScripts(script_arr, '/mypath/').done(function() {
    // all scripts loaded
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsozhenView Question on Stackoverflow
Solution 1 - JavascriptadeneoView Answer on Stackoverflow
Solution 2 - JavascriptAndreiView Answer on Stackoverflow
Solution 3 - JavascriptFrankeyView Answer on Stackoverflow
Solution 4 - JavascriptSalman AView Answer on Stackoverflow
Solution 5 - JavascriptChris PrattView Answer on Stackoverflow
Solution 6 - JavascriptMarcView Answer on Stackoverflow
Solution 7 - JavascriptEmanuel KlugeView Answer on Stackoverflow
Solution 8 - JavascriptRoccoBView Answer on Stackoverflow
Solution 9 - JavascriptMaciej SawickiView Answer on Stackoverflow
Solution 10 - JavascriptH4dr1enView Answer on Stackoverflow
Solution 11 - JavascriptdqhendricksView Answer on Stackoverflow
Solution 12 - JavascriptMr_GreenView Answer on Stackoverflow
Solution 13 - Javascriptuser2020001View Answer on Stackoverflow
Solution 14 - JavascriptWhelkaholismView Answer on Stackoverflow
Solution 15 - Javascriptuser3455212View Answer on Stackoverflow
Solution 16 - Javascriptuser669677View Answer on Stackoverflow
Solution 17 - JavascriptdjangoView Answer on Stackoverflow
Solution 18 - JavascriptRickView Answer on Stackoverflow
Solution 19 - JavascriptEugeneView Answer on Stackoverflow