如何使用jQuery $ .getScript()方法包含多个js文件

我想dynamic包括JavaScript文件到我的js文件。 我做了一些研究,发现jQuery $ .getScript()方法将是一个理想的方式去。

// 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? }); 

但我想知道这种方法是否可以一次加载多个脚本? 为什么我问这是因为有时我的javascript文件是依赖于多个js文件。

先谢谢你。

答案是

你可以在getScript()使用promise,并等待所有的脚本加载getScript() ,如下所示:

 $.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

在上面的代码中,添加Deferred并在$()parsing它就像在$(func)放置任何其他函数一样,它和

 $(function() { func(); }); 

即它等待DOM准备就绪,所以在上面的例子中$.when等待所有的脚本被加载, 并且 DOM准备就绪,因为$.Deferred调用在DOM就绪callback中parsing。


为了更通用的使用,一个方便的function

接受任何脚本数组的实用程序函数可以像这样创build:

 $.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); } 

可以这样使用

 var script_arr = [ 'myscript1.js', 'myscript2.js', 'myscript3.js' ]; $.getMultiScripts(script_arr, '/mypath/').done(function() { // all scripts loaded }); 

这个path将被加在所有的脚本之前,也是可选的,这意味着如果数组包含完整的URL,那么也可以这样做,并且把path全部放在一起

 $.getMultiScripts(script_arr).done(function() { ... 

参数,错误等

另外,请注意donecallback将包含许多匹配传入脚本的参数,每个参数表示包含响应的数组

 $.getMultiScripts(script_arr).done(function(response1, response2, response3) { ... 

每个数组将包含类似[content_of_file_loaded, status, xhr_object] 。 我们通常不需要访问这些参数,因为无论如何都会自动加载脚本,大部分时间, donecallback是我们真的知道所有脚本都已经加载后,我只是将它添加完整性,以及在需要访问加载文件的实际文本或需要访问每个XHR对象或类似的情况的罕见情况下。

另外,如果任何脚本加载失败,失败处理程序将被调用,并且后续脚本将不会被加载

 $.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 }); 

我实现了一个简单的函数来并行加载多个脚本:

function

 function getScripts(scripts, callback) { var progress = 0; scripts.forEach(function(script) { $.getScript(script, function () { if (++progress == scripts.length) callback(); }); }); } 

用法

 getScripts(["script1.js", "script2.js"], function () { // do something... }); 

在以前的callback中加载以下所需的脚本,如下所示:

 $.getScript('scripta.js', function() { $.getScript('scriptb.js', function() { // run script that depends on scripta.js and scriptb.js }); }); 

使用yepnope.js或Modernizr (包括yepnope.js作为Modernizr.load )。

UPDATE

为了跟进,这里有一个相当于你现在使用yepnope的东西,显示了对多个脚本的依赖关系:

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

我碰到了多个脚本加载的问题,包括一个问题(至less在Chrome中),同样的域名热负载的脚本没有实际运行后成功加载的Ajax在跨域工程完美罚款! 🙁

对原始问题的select答案不能可靠地工作。

在许多迭代之后,这里是我对getScript(s)的最终答案,并以特定的严格顺序asynchronous加载多个脚本,每个脚本加载callback选项和整体callback完成后,在jQuery 2.1+和现代版本的Chrome,Firefox加上被遗弃的Internet Explorer。

我的testing用例是为THREE.JS webGL渲染加载文件,然后在使用间隔检查传递给匿名函数调用onComplete的THREE全局变为可用时启动渲染脚本。

Prototype函数(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(); }; 

如何使用

 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(); 

这个函数就像我发现使用Deferred(现在已经弃用了吗?),当我的试验中的成功和完成不是100%可靠!因此,这个函数和statusCode的使用,例如。

如果您愿意,您可能需要添加错误/失败处理行为。

你可以通过尝试下面的函数来使用$.when -method:

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

这个function可以这样使用:

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

这是使用承诺的方式,并具有最小的开销。

很好的答案,adeneo。

我花了一点时间才弄清楚如何让你的答案更通用(这样我可以加载一个代码定义的脚本数组)。 当所有脚本都被加载并执行时,callback被调用。 这是我的解决scheme:

  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(); } }); } 

你正在寻找的是一个AMD兼容的加载器(如require.js)。

http://requirejs.org/

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

如果你仔细查看,有许多好的开源软件。 基本上这允许你定义一个代码模块,如果它依赖于其他代码模块,它将等待,直到这些模块已经完成下载,然后继续运行。 这样,你可以asynchronous加载10个模块,即使依赖其他几个模块运行也不会有问题。

这个函数将确保在完成加载依赖文件之后加载文件。 您只需按顺序提供文件,同时牢记其他文件的依赖关系。

 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); } 

有时需要按特定顺序加载脚本。 例如,你不能在jQuery之前加载jQuery UI。 这个页面上的大多数例子并行地(asynchronous地)加载脚本,这意味着不能保证哪个脚本首先被执行。

我提出了一个混合的方法,允许顺序加载依赖的脚本+可选的并行加载+ 延期的对象 :

 function loadScripts(scripts, callback) { var deferred = $.Deferred(); function loadScript(scripts, callback, i) { $.ajax({ url: scripts[i], dataType: "script", cache: true, success: function() { if (i + 1 < scripts.length) { loadScript(scripts, callback, i + 1); } else { if (callback) { callback(); } deferred.resolve(); } } }); } loadScript(scripts, callback, 0); return deferred; } 

用法示例:

 function loadScripts(scripts, callback) { var deferred = $.Deferred(); function loadScript(scripts, callback, i) { $.ajax({ url: scripts[i], dataType: "script", cache: true, success: function() { if (i + 1 < scripts.length) { loadScript(scripts, callback, i + 1); } else { if (callback) { callback(); } deferred.resolve(); } } }); } loadScript(scripts, callback, 0); return deferred; } // queue #1 - jquery ui and jquery ui i18n files var d1 = loadScripts([ "http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js", "http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/i18n/jquery-ui-i18n.min.js" ], function() { $("#datepicker1").datepicker($.datepicker.regional.fr); }); // queue #2 - jquery cycle2 plugin (no callback required) var d2 = loadScripts([ "malsup/cycle2/2.1.6/build/jquery.cycle2.min.js" ]); // optional, trigger a callback when all queues are complete $.when(d1, d2).done(function() { console.log("All scripts loaded"); }); 
 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <p><input id="datepicker1"></p> <div class="cycle-slideshow" data-cycle-log="false"> <img src="http://dummyimage.com/300x100/000/aaa"> <img src="http://dummyimage.com/300x100/333/ccc"> <img src="http://dummyimage.com/300x100/666/fff"> </div> 

这适用于我:

 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; }); } 

并使用它:

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

上面的安德鲁马克牛顿的综合答案更短的版本。 这不会检查成功的状态代码,您应该这样做以避免未定义的UI行为。

这是一个令人讨厌的系统,我可以保证jQuery,但没有其他包括,所以我想要一个足够短的技术,如果被迫进入它不被养殖到外部脚本。 (通过将索引0传递给第一个“recursion”调用,可以使得它更短,但风格习惯的力量使我添加了糖)。

我还将依赖项列表分配给模块名称,因此可以将此块包含在需要“module1”的任何位置,并且脚本和相关初始化将仅包含/运行一次(您可以在callback中loggingindex并查看单个有序的一组AJAX请求运行)

 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); } 

有一个插件扩展了jQuery的getScript方法。 允许asynchronous和同步加载,并使用jQuery的caching机制。 充分披露,我写了这个。 如果您find更好的方法,请随时投稿。

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

n个脚本逐一加载(例如,如果第二个文件需要第一个文件,则可用):

 (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')}); 

基于上面的@ adeneo的答案:结合加载的CSS和JS文件

任何改进build议?

 // 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); 

使用async = false附加脚本

这是一个不同的,但超级简单的方法。 要加载多个脚本,您可以简单地将它们附加到正文。

  • 加载它们是asynchronous的,因为这是浏览器优化页面加载的方式
  • 按顺序执行脚本,因为这是浏览器parsingHTML标记的方式
  • 不需要callback,因为脚本是按顺序执行的。 只需添加另一个脚本,它将在其他脚本之后执行

更多信息在这里: 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); });