当前位置: 代码迷 >> Web前端 >> 模拟jQuery.Deferred实现
  详细解决方案

模拟jQuery.Deferred实现

热度:514   发布时间:2013-12-22 15:06:55.0
模拟jQuery.Deferred实现!
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(此方法可用于许多其他场景)
  相关解决方案