@Felix Kling 的回答是一个很好的开始。但是,我发现如果我想“功能化”它.done()
,在返回结果末尾附加的整体存在一个小问题。您需要循环内.getScripts()
链式迭代的最后一个承诺。.getScript()
这是他的解决方案的修改版本(谢谢,顺便说一句)。
插入:
(function ($) {
var fetched = new function () {
this.scripts = [];
this.set = [];
this.exists = function (url) {
var exists = false;
$.each(this.set, function (index, value) {
if ((url || '') === value) {
exists = true;
return false;
}
});
return exists;
};
this.buildScriptList = function () {
var that = this;
that.set = [];
$('script').each(function () {
var src = $(this).attr('src') || false;
if (src) {
that.set.push(src);
}
});
$.merge(this.set, this.scripts);
return this;
};
},
getScript = $.getScript;
$.getScript = function () {
var url = arguments[0] || '';
if (fetched.buildScriptList().exists(url)) {
return $.Deferred().resolve();
}
return getScript
.apply($, arguments)
.done(function () {
fetched.scripts.push(url);
});
};
$.extend({
getScripts: function (urls, cache) {
if (typeof urls === 'undefined') {
throw new Error('Invalid URL(s) given.');
}
var deferred = $.Deferred(),
promise = deferred.promise(),
last = $.Deferred().resolve();
if (!$.isArray(urls)) {
urls = [urls];
}
$.each(urls, function (index) {
promise = promise.then(function () {
last = $.getScript(urls[index]);
return last;
});
});
if (Boolean(cache || false) && !Boolean($.ajaxSetup().cache || false)) {
$.ajaxSetup({cache: true});
promise.done(function () {
$.ajaxSetup({cache: false});
});
}
deferred.resolve();
return last;
}
});
})($);
您可以忽略 fetched 函数(我实现它以减少潜在的冗余调用 - 这就是我劫持的原因.getScript()
)并查看变量在方法last
内的设置位置.getScripts()
。它默认为已解析的延迟对象,因此如果 urls 数组为空,则将其传递给返回的结果以附加外部.done()
调用。否则,它将不可避免地从链式.getScript()
调用中分配到最后一个 Promise 对象,从而确保所有内容从函数外部保持同步。
如果您在将其返回给调用者之前将其解析,则返回最初创建的延迟对象将不起作用(这是您应该按照jQuery 的官方文档执行的操作)。
例子:
function loadStuff(data) {
var version = {
'accounting': '1.2.3',
'vue': '1.2.3',
'vueChart': '1.2.3'
};
$.getScripts([
'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/' + version.accounting + '/accounting.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue/' + version.vue + '/vue.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue-chartjs/' + version.vueChart + '/vue-chartjs.min.js'
], true)
.done(function () {
// do stuff
})
.fail(function () {
throw new Error('There was a problem loading dependencies.');
});
}