关于Deferred对象,建议先看一下阮一峰老师的《jQuery的deferred对象详解》
看完之后,相信你对Deferred已经有所了解,如果你还想继续阅读下面的源码,可以先自己看下jQuery.Callbacks,或者先参考我前一篇文章:《学习jQuery.Callbacks》
完后再看下面的源码注释,相信你会发现,所谓的Deferred,其实就是构建了2条Callbacks的回调list,如下:
var calresolve = $.Callbacks('once memory'),
calreject = $.Callbacks('once memory'),
calnotify = $.Callbacks('memory');
var state = function(){
state = stateString;
}
calresolve.add(state,calreject.disable,calnotify.lock);
calreject.add(state,calresolve.disable,calnotify.lock);
当我们var def = $.Deferred()时,就已经生成了上面的两条list。我们还会发现,其实done/fail就是add,而resolve和reject就是fire。所以,当我们每次执行resolve或reject时,最少要执行3个回调,加上你新添加的回调(done||fail),分别是设置状态值state和将另一种状态禁用和锁定。这样就不会在你成功done时还能输出fail。看下面代码:
var fn1 = function(value){
alert('fn1:' + value)
}
var def = $.Deferred();
def.done(fn1); //相当于$.Callbacks('once memory').add(fn1)
def.resolve('littledu'); //相当于$.Callbacks('once memory').fire('littledu')
Deferred的原理也就大概如此。知道是怎么回事后,再重新看源码,会发现一切都很清晰。其他的api就不介绍了,直接上源码注释吧,都是个人学习理解,如果有同学看到这里,请辨证的看,不包正确,被我误导不负责任嘻嘻。
Deferred: function( func ) {
//声明一个二维数组,分别存放3个状态的数组,需先了解jQuery.Callbacks。
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
state = "pending", //回调状态值,分别有pending,resolved和rejected
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
function() {
var returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
}
} :
newDefer[ action ]
);
});
fns = null;
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {}; //声明deferred对象
// Keep pipe for back-compat
promise.pipe = promise.then;
// Add list-specific methods
//
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ], //保存Callbacks对象
stateString = tuple[ 3 ]; //保存状态值
// promise[ done | fail | progress ] = list.add
// 给promise添加方法,分别为done,fail,progress,绑定对应Callbacks的add方法,相当于调用deferred对象的done,fail,progress时,都是调用其Callbacks对象的add方法。
// promise.done = list.add
// promise.fail = list.add
// promise.progress = list.add
promise[ tuple[1] ] = list.add;
// Handle state
// action, add listener, listener list, final state
//[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
//[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
//将状态函数等扔进队列
if ( stateString ) { //stateString只有前两个数组有值,为前两个数组的Callbacks对象添加回调,均有一个存储state的匿名函数和另外两个Callbacks方法。其中第一个数组添加的是第二个数组的Callbacks对象的disable方法,第二个添加的是第一个数组的Callbacks对象的disable方法。lock方法则均为第3个数组的Callbacks对象所有
//[state,reject.disable,notify.lock]
//[state,resolve.disable,notify.lock]
//var dfd = $.Deferred();
//dfd.done(fn1) => [state,reject.disable,notify.lock,fn1]
//dfd.state() => 在执行done的时候,第一个匿名函数就是设置state值的
list.add(function() {
// state = [ resolved | rejected ]
state = stateString;
// [ reject_list | resolve_list ].disable; progress_list.lock
// 0^1=1 1^1=0
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
// deferred[ resolve | reject | notify ] = list.fire
// 这里,相当于deferred对象调用resolve,reject,notify时,都执行回调队列里的回调
deferred[ tuple[0] ] = list.fire;
deferred[ tuple[0] + "With" ] = list.fireWith;
});
// Make the deferred a promise
// 将promise的方法推入deferred,此时promise有的deferred都有,deferred有的promise不一定有,如resolve和reject
promise.promise( deferred );
// Call given func if any
// 如果jQuery.Deferred(fn)有传入函数,则会执行这里,函数的context将会是deferred,参数也是deferred,在then中有用到,也可以外部直接传入函数中使用
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
// Deferred helper
// when,可以理解为deferred的一个中转站,比如我有一个函数,我要在这个函数执行完后再触发回调,when就是做这样的工作,它需要这个函数返回deferred对象,然后返回的是deferred.promise对象,从而可以实现$.when(fn).done(fnDone)的链式操作,因为done其实也就是Callbacks.add,所以这里相当于fnDone这个回调push进回调数组,然后在所传的函数里面有一句resolve()或reject()执行一下回调数组,从而触发回调。就是这样。
// PS:对于when我还有很多不明白,比如传多个函数,有人说要两个函数都resolve,才能执行done,但我测试回调的done或fail是以第一个函数为准的,也就是说如果它为resolve,那么回调会进入done,否则则进入fail,还有待观察
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ), //将deferred对象转化为数组
length = resolveValues.length,
// the count of uncompleted subordinates
// 如果length不等于1,则直接返回length,如果length==1,则要看所传的函数是不是deferred对象,如果不是返回0,是的话返回length(1)
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
// 如果remaining==1,则说明所传函数是deferred对象,直接使用它,否则重新创建一个新的deferred对象
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
// Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
if( values === progressValues ) {
deferred.notifyWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
},
progressValues, progressContexts, resolveContexts;
// add listeners to Deferred subordinates; treat others as resolved
// 当所传函数不止一个时,情况较复杂,这里我也是很多不明
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )
.progress( updateFunc( i, progressContexts, progressValues ) );
} else {
--remaining;
}
}
}
// if we're not waiting on anything, resolve the master
// 如果所传函数不是deferred对象,则立即执行回调,这里用了resolveWidth,表明执行的都是done方法,resolveContexts为undefined,表明回调执行的上下文在window
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
return deferred.promise();
}
