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

我试图将 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 文件。

先谢谢你。

136753 次浏览

使用 没错 Js现代化(其中包括 yepnope.js 作为 Modernizr.load)。

更新

仅仅是跟进,这里有一个很好的相当于您目前使用 yepnope 的东西,显示了对多个脚本的依赖性:

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

您正在寻找的是一个与 AMD 兼容的加载程序(如 Reque.js)。

Http://requirejs.org/

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

如果你查一下,有很多很好的开源软件。基本上,这允许您定义一个代码模块,如果它依赖于其他代码模块,那么它将等到这些模块完成下载之后再继续运行。这样,您可以异步加载10个模块,即使一个模块依赖于其他一些模块来运行,也不会出现任何问题。

答案是

您可以在 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
    

});

小提琴

另一个小提琴

在上面的代码中,添加一个 Deferred 并在 $()中解析它,就像在 jQuery 调用中放置任何其他函数一样,比如 $(func),它与

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

例如,它等待 DOM 就绪,因此在上面的示例中,$.when等待所有加载的脚本 还有,以便 DOM 就绪,因为 $.Deferred调用在 DOM 就绪回调中解析。


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

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

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

其中路径将被预先写入所有脚本,并且也是可选的,这意味着如果数组包含完整的 URL 的一个也可以这样做,并省略了所有的路径

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

争论、错误等。

另外,请注意,done回调将包含许多与脚本中传递的参数相匹配的参数,每个参数表示一个包含响应的数组

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

其中每个数组将包含类似于 [content_of_file_loaded, status, xhr_object]的内容。 我们通常不需要访问这些参数,因为脚本无论如何都会被自动加载,而且大多数时候,done回调是我们真正想要知道的所有脚本都已经加载,我只是为了完整性添加它,并在极少数情况下需要访问加载文件中的实际文本,或者需要访问每个 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
});

在前一个回调中加载所需的后续脚本,如:

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

我遇到了一些问题与多脚本加载包括一个问题(至少在 Chrome)同一域热加载脚本实际上没有运行后,成功加载的 Ajax 跨域工作非常好!:(

原始问题的选定答案不能可靠地工作。

在经过多次迭代之后,这里是我对 getScript 的最终回答,它按照特定的严格顺序异步加载多个脚本,包括每个脚本加载回调选项和完成时的整体回调,测试了 jQuery 2.1 + 和现代版的 Chrome,Firefox 以及被抛弃的 Internet Explorer。

我的测试用例是加载 THREE.JS webGL 呈现的文件,然后在 THREE global 可用时启动呈现脚本,方法是使用传递给 onComplete 的匿名函数调用的间隔检查。

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

该函数与我使用延迟(现在已弃用?)找到的函数一样什么时候,成功和完成我的试验不是100% 可靠! ?,因此这个函数和 statusCode 的使用例如。

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

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

这是一个恼人的系统,我可以保证 jQuery,但没有其他包括,所以我想要一个技术足够短,不会被强制成一个外部脚本。(您可以通过将索引0传递给第一个“递归”调用来使它更短,但风格习惯的力量让我添加了糖)。

我还将依赖项列表分配给一个模块名称,因此这个块可以包含在任何需要“ module1”的地方,并且脚本和依赖项初始化只包含/运行一次(您可以在回调中记录 index,然后看到一组有序的 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 方法。允许异步和同步加载,并使用 jQuery 的缓存机制。说实话,这是我写的。如果你找到更好的方法,请随意贡献。

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

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

功能

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

您可以通过尝试以下函数来使用 $.when方法:

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

这个函数可以这样使用:

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

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

一个接一个地加载 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')});

此函数将确保在完全加载依赖项文件之后加载文件。您只需要按顺序提供这些文件,同时牢记对其他文件的依赖性。

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

答得好,阿德尼奥。

我花了一点时间才弄明白如何使您的答案更通用(这样我就可以加载一组代码定义的脚本)。当所有脚本都已加载并执行时,将调用回调。我的解决办法是:

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

有时需要按照特定的顺序加载脚本。例如,jQuery 必须在 jQueryUI 之前加载。这个页面上的大多数示例以并行(异步)方式加载脚本,这意味着不能保证执行顺序。如果没有顺序,那么如果两者都成功加载但顺序错误,那么依赖于 x的脚本 y可能会中断。

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

/*
* 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>

两个队列中的脚本将并行下载,但是,每个队列中的脚本将按顺序下载,以确保有序执行。瀑布图:

waterfall chart of scripts

基于上面@adeneo 的回答: 组合加载 css 和 js 文件

有什么改进的建议吗?

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

这对我有用:

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

在脚本后面添加异步 = false

这里有一个不同的,但超级简单的方法。 要加载多个脚本,只需将它们附加到 body。

  • 异步加载它们,因为浏览器就是这样优化 页面加载
  • 按顺序执行脚本,因为浏览器就是这样解析 HTML 标记的
  • 不需要回调,因为脚本是按顺序执行的。只需添加另一个脚本,它将在其他脚本之后执行

更多信息请点击: 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);
});

下面是使用 Maciej Sawicki 的1并实现 Promise作为回调的答案:

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

用途:

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


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

所有 Javascript 文件都会尽快下载并按照给定的顺序执行,然后调用 taskNeedingParameters

您可以尝试使用递归。这将同步下载它们,一个接一个,直到完成整个列表的下载。

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

我已经改进了@adeneo 脚本,所以它将按照指定的顺序加载所有脚本。它不做链式装载,所以它非常快,但如果你想更快,改变50毫秒的等待时间。

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

用法相同:

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


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