这是一个相对安全的方法( demo ),它使用Deferred
s,在 IE 6-9、Chrome 19 和 Firefox 3.6-10、Opera 10.10-11.52、Android 4 和 iOS 5 中测试和工作。
首先,我们将编写一个小型 jQuery 插件,它Deferred
为 jQuery 集合中的每个元素返回一个 s 数组。当元素加载时,每个Deferred
都会被解析;如果元素加载失败或(可选)花费的时间超过timeout
几秒钟,则拒绝。
$.fn.loaded = function(opts) {
var o = $.extend({timeout:10000}, opts) // Merge default options with supplied options
, r = []; // Return value
this.each(function() {
var dfd = new $.Deferred(), el = $(this), to;
if (o.timeout) to = setTimeout(function() {
done();
dfd.reject();
}, o.timeout);
el.bind('load.dfdl', function() {
done();
dfd.resolve();
}).bind('error.dfdl', function() {
done();
dfd.reject();
});
function done() { // internal clean-up
clearTimeout(to);
el.unbind('.dfdl');
}
r.push(dfd.promise());
});
return r;
};
超时将防止浏览器实际上从未触发任何事件的情况。我在这里将默认超时设置为 10 秒;在现实世界中,您可能希望减少它。
现在我们将生成 10 个随机大小的placekittens,用作示例中的图像。
var imgs=[];
for (var i = 0; i < 10; i++) imgs.push('<img src="http://placekitten.com/' + rnd() + '/' + rnd() + '"> ');
$('#imgs').html(imgs.join());
最后,我们将用一些魔法把所有东西放在一起:
$.when.apply($, $('#imgs img').loaded({timeout:10000}) ).done(function() {
alert('loaded successfully');
}).fail(function() {
alert('load failed or timed out');
});
$.when
创建一个Deferred
只有在其所有子节点都解决时才解决的主Deferred
节点,或者在子节点拒绝时拒绝。它通常希望您将每个Deferred
作为参数传递(它不支持传入Deferred
s 数组),因此我们必须传入apply
我们的数组。(我可能会这样做$.whenall = function(dfds) { $.when.apply($,dfds); };
,以便您的应用程序代码更干净$.whenall( $('#imgs img').loaded() )...
)