jQuery:按顺序加载脚本

我正在尝试使用jQuery动态加载一些脚本:

var scripts = ['script1.js','script2.js','script3.js']; $.each(scripts , function(i, val) { $.getScript(val, function() { console.log('loaded '+ val); }); 

但有时加载脚本的顺序会发生变化。 如何在上一个脚本成功加载后加载每个脚本?

您可以使用$.getScript()的回调函数作为递归函数调用,在上一次加载完成后加载每个。

 //setup array of scripts and an index to keep track of where we are in the process var scripts = ['script1.js','script2.js','script3.js'], index = 0; //setup a function that loads a single script function load_script() { //make sure the current index is still a part of the array if (index < scripts.length) { //get the script at the current index $.getScript(scripts[index], function () { //once the script is loaded, increase the index and attempt to load the next script console.log('Loaded: ' + scripts[index]); index++; load_script(); }); } } 

代码中发生的是脚本同时被请求,并且由于它们异步加载,它们以随机顺序返回和执行。

更新

我没有对此进行测试,但是如果脚本是本地托管的,那么您可以尝试以纯文本格式检索脚本,然后将所有代码存储在变量中,直到它们全部加载为止,此时您可以按顺序评估脚本:

 var scripts = ['script1.js','script2.js','script3.js'], //setup object to store results of AJAX requests responses = {}; //create function that evaluates each response in order function eval_scripts() { for (var i = 0, len = scripts.length; i < len; i++) { eval(responses[scripts[i]]); } } $.each(scripts, function (index, value) { $.ajax({ url : scripts[index], //force the dataType to be `text` rather than `script` dataType : 'text', success : function (textScript) { //add the response to the `responses` object responses[value] = textScript; //check if the `responses` object has the same length as the `scripts` array, //if so then evaluate the scripts if (responses.length === scripts.length) { eval_scripts(); } }, error : function (jqXHR, textStatus, errorThrown) { /*don't forget to handle errors*/ } }); }); 

您可以利用$.getScript (以及所有其他Ajax方法)返回的jqXhr对象实现Promise接口的.pipe() ,因此提供了.pipe() ,可用于链接延迟对象:

 var deferred = new $.Deferred(), pipe = deferred; $.each(scripts , function(i, val) { pipe = pipe.pipe(function() { return $.getScript(val, function() { console.log('loaded '+ val); }); }); }); deferred.resolve(); 

有关更多信息,请查看延迟对象和deferred.pipe

总的来说,使用延迟对象可以提供更大的灵活性,并且可以让您更轻松地添加error handling程序。

@Jasper解决方案的增强版:

  • 使用$.when同步调用。
  • 使用全局评估。

这是代码:

 /** * Load scripts in parallel keeping execution order. * @param {array} An array of script urls. They will parsed in the order of the array. * @returns {$.Deferred} */ function getScripts(scripts) { var xhrs = scripts.map(function(url) { return $.ajax({ url: url, dataType: 'text', cache: true }); }); return $.when.apply($, xhrs).done(function() { Array.prototype.forEach.call(arguments, function(res) { eval.call(this, res[0]); }); }); } 

这个要点: https : //gist.github.com/ngryman/7309432 。

有些脚本的大小可能会有所不同,因此无法预测。 尝试这样的事情。

 var scripts = ['script1.js','script2.js','script3.js'], ScriptIndex = 0; function LoadScript(index){ if(index >= scripts.length) return; $.getScript(scripts[index], function(){ console.log('Loaded script '+ scripts[index]); LoadScript(++ScriptIndex); } } 

这应该在最后一个脚本完全加载后加载每个脚本。 确保通过调用函数LoadScript(0);启动它LoadScript(0);

你可以sort()数组 –

 var sorted = scripts.sort(); 

然后在每个函数中使用sorted。

@ ngryman的解决方案存在一个小问题; 如果要加载的url数组中只有一个url,则.done()函数的参数param将是一个单维数组,而不是2维数组。 你需要在循环之前检查参数,因此:

 /** * Load scripts in parallel keeping execution order. * @param {array} An array of script urls. They will parsed in the order of the array. * @returns {$.Deferred} */ function getScripts(scripts) { var xhrs = scripts.map(function(url) { return $.ajax({ url: url, dataType: 'text', cache: true }); }); return $.when.apply($, xhrs).done(function() { if (arguments.length == 3 && typeof arguments[0] == "string") { arguments = [arguments]; } Array.prototype.forEach.call(arguments, function(res) { eval.call(this, res[0]); }); }); } 

为新答案道歉,没有足够的代表发表评论@ ngryman的答案,但认为它可能会帮助某人!