我正在开发一个更好的$.getScript
函数版本,它可以:
您可能会建议一些库,例如requirejs或LABjs,但我想我可以通过使用jQuery Deferred对象来创建类似的库。这是我到目前为止的尝试:
(function($) {
'use strict';
var cachedScriptPromises = {};
$.require = function(url, callback, errback) {
var urls = (url instanceof Array) ? url : [url],
promises = [];
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
if ( ! cachedScriptPromises[url]) {
cachedScriptPromises[url] = $.Deferred(function(defer) {
$.ajax({
dataType: 'script',
cache: true,
url: url
}).then(defer.resolve, defer.reject);
}).promise();
}
promises.push(cachedScriptPromises[url]);
}
$.when.apply($, promises).done(callback).fail(errback);
};
})(jQuery);
这个想法是为每个脚本url存储一个promise对象,然后在解析所有延迟对象时触发回调。
我不知道如何正确测试这个功能但是请看一下这个测试页面,如果你多次刷新页面,可能会丢失其中一个输出(在Chrome上比在Firefox上更常出现) )。
更新 - 以下是我的测试用例之一,有时候没有记录任何内容:
$.require(['jquery.log.js', 'foo.js'], function() {
$('#log').log('jquery.log.js and foo.js were loaded!');
});
jquery.log.js:
(function($) {
$.fn.log = function(msg) {
this.each(function() {
$(this).append('<p>' + msg + '</p>');
});
};
})(jQuery);
foo.js:
$('#log').log('Foo!');
我的$.require
功能有什么问题吗?
答案 0 :(得分:0)
问题是jquery.log.js和foo.js会并行加载。如果首先加载foo.js,则会抛出错误(日志函数未定义)。所以我必须把$.require
放在foo.js上:
$.require('jquery.log.js').done(function() {
$('#log').log('Foo!');
});
关于我使用jQuery Deferred对象做的问题,以下是@Benjamin Gruenbaum建议的一些更改:
$.ajax
返回一个承诺,因此不需要将其包装在新的延迟对象中。$.require
函数应该返回一个promise,而不是使用callback / errback。 $.require
功能:
(function($) {
'use strict';
var cachedScriptPromises = {};
$.require = function(url) {
var urls = (url instanceof Array) ? url : [url],
promises = [];
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
if ( ! cachedScriptPromises[url]) {
cachedScriptPromises[url] = $.ajax({
dataType: 'script',
cache: true,
url: url
});
}
promises.push(cachedScriptPromises[url]);
}
return $.when.apply($, promises);
};
})(jQuery);