如何使用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() { ...
参数,错误等
另外,请注意done
callback将包含许多匹配传入脚本的参数,每个参数表示包含响应的数组
$.getMultiScripts(script_arr).done(function(response1, response2, response3) { ...
每个数组将包含类似[content_of_file_loaded, status, xhr_object]
。 我们通常不需要访问这些参数,因为无论如何都会自动加载脚本,大部分时间, done
callback是我们真的知道所有脚本都已经加载后,我只是将它添加完整性,以及在需要访问加载文件的实际文本或需要访问每个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/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更好的方法,请随时投稿。
将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); });