var _Deferred=function(){
var callbacks=[],fired;
var method={
done:function(func){
callbacks.push(func);
if(fired){
method.resolveWith(fired[0],fired[1]);
}
return this
},
resolveWith:function(context,args){
args=args || [];
fired=[context,args];
while(callbacks[0]){
callbacks.shift().apply(context,args);
}
return this;
},
resolve:function(){
method.resolveWith(this,arguments);
return this;
}
}
return method;
}
var Deferred=function(){
var doneDeferred=_Deferred(),failDeferred=_Deferred();
$.extend(doneDeferred,{
reject:failDeferred.resolve,
rejectWidth:failDeferred.resolveWith,
fail:failDeferred.done,
always:function(func){
doneDeferred.done(func).fail(func);
},
promise:function(){
return {
done:doneDeferred.done,
fail:doneDeferred.fail,
always:doneDeferred.always,
promise:doneDeferred.promise
};
}
});
return doneDeferred;
}
var when=function(deferredItem){
var args=arguments,length=arguments.length,count=length;
var deferred=(length<=1&&deferredItem&&deferredItem.promise)?deferredItem:Deferred();
if(deferred!=deferredItem){
var doneBack=function(i){
return function(value){
args[i]=arguments.length>1?[].slice.call(arguments,0):value;
if(!(--count)){
deferred.resolveWith(deferred,args);
}
}
}
for(var i=0;i<arguments.length;i++){
if(arguments[i] && arguments[i].promise){
arguments[i].done(doneBack(i)).fail(deferred.reject);
}else{
count--;
}
}
if(!count){
deferred.resolveWith(deferred,args);
}
}
return deferred.promise();
}
//测试
function wait(){
var df=Deferred();
setTimeout(function(){
alert('end wait..');
df.reject();
},2000);
return df.promise();
}
function wait2(){
var df=Deferred();
setTimeout(function(){
df.resolve();
},4000);
return df.promise();
}
function f1(){
alert('ttt');
}
when(wait(),wait2()).done(function(){
f1();
});
延迟对象jQuery.Deferred()设计思想:
1)函数队列,done与fail各维护一个!(抽离出来封装一个闭包)
3)done/fail的时候把新的函数放进对应的函数队列
3)resolve的时候循环shift并调用done函数队列;reject的时候循环shift并调用fail函数队列
4)利用标志变量fired存储resolve或reject的上下文和参数,可用于判断deferred是否已resolve或reject,以及传递上下文和参数!(这样一来,done/fail方法在resolve/reject后面执行也不怕了)
5)when方法:判断是否所有deferred已resolve的时候,很巧妙地利用了count记数法,resolve一个count减去1(此方法可用于许多其他场景)