基于jquery-2.0.3的源码学习
//10. Deferred : 延迟对象 : 对异步的统一管理
jQuery.extend({
Deferred: function(func){
// once表示回调函数列表只能被触发一次,memory表示会记录上一次触发回调函数列表时的参数,
//触发后添加的任何回调函数都将用记录的参数值立即调用。
//tuples 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态
var tuples =[
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
// 初始状态。异步队列的初始状态为待定pending。
//变量state在调用方法deferred.resolve()或deferred.resolveWidth()后被设置为字符串“resolved”,
//表示成功状态,调用方法deferred.reject()或deferred.rejectWith()后被设置为字符串“rejected”,表示失败状态。
state = "pending",
//创建了一个promise对象,具有state、always、then、primise方法
promise = {
// deferred.state()用于返回异步队列的状态。
// 如果方法deferred.state()返回“resolved”,意味着deferred.resolve()或者deferred.resolveWith()已经被调用,
//成功回调函数已经执行或者正在执行;如果方法deferred.state()返回“rejected,
//意味着deferred.reject()或者deferred.rejectWith()已经被调用,并且失败回调函数已经执行或者正在执行;
state:function(){
//确定一个Deferred对象的当前状态
//deferred.state()方法返回一个字符串,代表Deferred对象的当前状态。 Deferred对象可以在三种状态之一:
//pending: Deferred对象是尚未完成状态 (不是 "rejected" 或 "resolved").
//resolved: Deferred对象是在解决状态,这意味着,deferred.resolve() 或者
//deferred.resolveWith()被对象访问和doneCallbacks被访问(或在被调用的过程中) 。
//rejected: Deferred对象是在被拒绝的状态,这意味着,deferred.reject() 或者
//deferred.rejectWith() 被对象访问和failCallbacks被访问(或在被调用的过程中) 。
return state
},
// 在便捷方法always()中,采用链式语法依次调用方法done()、fail()重复添加回调函数,
//并返回this以继续支持链式语法。调用方法done()、fail()时,关键字this始终指向当前异步队列,
//因此实际上不借用方法apply()也可以用链式语法。
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 = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
deferred[ tuple[1] ](function() {
var returned = fn && 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 === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
});
fns = null;
}).promise();
},
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
promise.pipe = promise.then;
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
stateString = tuple[ 3 ];
// promise[ done | fail | progress ] = list.add
promise[ tuple[1] ] = list.add;
// Handle state
if ( stateString ) {
list.add(function() {
// state = [ resolved | rejected ]
state = stateString;
// [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
// deferred[ resolve | reject | notify ]
deferred[ tuple[0] ] = function() {
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
deferred[ tuple[0] + "With" ] = list.fireWith;
});
promise.promise( deferred );
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
// the count of uncompleted subordinates
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
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
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
return deferred.promise();
}
});
//10. Deferred : 延迟对象 : 对异步的统一管理