本系列文章都是基于jquery1.6.4的,请参照源代码。
今天,我们来研究jQuery._Deferred方法。和往常一样,先放源代码。
jQuery.extend({
// Create a simple deferred (one callbacks list)
_Deferred: function() {
var // callbacks list
callbacks = [],
// stored [ context , args ]
fired,
// to avoid firing when already doing so
firing,
// flag to know if the deferred has been cancelled
cancelled,
// the deferred itself
deferred = {
// done( f1, f2, ...)
done: function() {
if ( !cancelled ) {
var args = arguments,
i,
length,
elem,
type,
_fired;
if ( fired ) {
_fired = fired;
fired = 0;
}
for ( i = 0, length = args.length; i < length; i++ ) {
elem = args[ i ];
type = jQuery.type( elem );
if ( type === "array" ) {
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
}
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// resolve with given context and args
resolveWith: function( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || [];
firing = 1;
try {
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );
}
}
finally {
fired = [ context, args ];
firing = 0;
}
}
return this;
},
// resolve with this as context and given arguments
resolve: function() {
deferred.resolveWith( this, arguments );
return this;
},
// Has this deferred been resolved?
isResolved: function() {
return !!( firing || fired );
},
// Cancel
cancel: function() {
cancelled = 1;
callbacks = [];
return this;
}
};
return deferred;
},
//下面是Deferred方法和when方法
Deferred: function( func ) {},
when: function( firstParam ) {}
)};
jQuery._Deferred方法是通过jQuery.extend方法加入到jQuery中的,关于jQuery.extend方法,请查看我的另外一篇博文(现在还没有写)。
从第5-13我们可以看出_Deferred函数对象拥有5个属性,分别是callbacks(数组),fired,firing,cancelled,deferred(对象)。
callbacks数组是存放_Deferred对象通过done方法注册的函数,这时候我们可以根据第34行和52行这两条语句,我们可以知道callbacks模拟了队列,因此通过done注册的回调函数,触发时回调函数是根据传入的顺序来执行的。
fired属性表示_Deferred对象是否已经是满足状态,根据第56行,我们可知道此时fired的值得形式是[context,args] (后面解释),而未满足状态的fired是undefined或者0。
firing=1(第50行)表示_Deferred对象正在从未满足状态转换到满足状态,防止_Deferred对象多次被resolve(第46行),当_Deferred对象为满足状态时,firing=0(第57行)。
cancelled属性表示_Deferred对象是否被取消,也就是是否可以注册回调函数,对于被取消的_Derferred对象是不可以触发和注册回调函数的。deferred对象是在_Deferred函数内定义的,最终被返回,实际_Defered对象就是指的deferred对象,这样是为了保护前面的四个变量;
deferred对象有done,resolve,resolveWith,isResolved,cancel这些函数。现在我们来分别看这5个函数,从最简单的开始:
cancel函数只有三句(76-78),把cancelled设为1,清空callback数组,被调用了cancelled的_Deferred对象是不可被触发的。
isResolved函数是判断_Deferred对象处于什么样的状态,当_Deferred对象处于满足状态(fired=[context,args])或者是正在从未满足状态到满足状态的转换过程中都是true,其他为false,这儿(第71行)有两个是为了在firing和fired都是undefined的时候返回true。
resolve函数可以传入参数,并把this(通常就是deferred对象)和传递进来的参数arguments传递给resolveWith函数。当触发是,实际真正处理的resolveWith函数(第65行)。下面我们来看看resolveWith函数。
resolveWith的函数的第一句(第46行):说明只有没有取消的并且_Deferred对象是未满足的才可以触发回调函数。第49行把firing设为1表示_Deferred对象正在从未满足状态转换为满足状态,而第51句的while循环和52行的callbacks.shift().apply(context,args),通过done注册的回调函数安装注册的顺序被触发。
下面是本篇文章的最重要的部分,done函数的分析。done函数的参数可以是函数,或者是元素是函数的数组;我们一句一句来分析done函数,第18-23行定义了六个变量,其中_fired变量是为了保存fired变量的值,防止fired变量被修改引起的副作用;我们知道_Defered对象是满足状态的时候,通过done注册的函数是会被立即执行的。这可以从第37-39知道,因为_Deferred对象是刚刚是满足的(第26行有fired=0),那么if(_fired)就会为真,然后会调用resolveWith方法;如果此时_Defered是正在转换的,那么第28-36行的回调函数已经被注册到了callbacks,那么现在通过done注册的回调函数也会被立即执行的(因为有另外一个resolveWith调用还没有完成);那我们现在来仔细看看注册回调函数的部分。
for循环对done的每一个参数进行处理,在for循环内,type表示了参数的类型,如果是数组(第31行),那么通过在进行一步的deferred.done.apply( deferred, elem )调用把数组内的函数(可以嵌套数组(语法来讲,当然我们也不会这么折腾自己),还有数组具有length属性,因此对于数组参数在进行done(这个时候只有一个数组参数)调用,可以再次通过for循环,把内部的函数注册到callbacks);如果type是函数那么直接调用callbacks.push,把回调函数放到callbacks的尾端。保证了回调函数的调用顺序。
今天的_Deferred理解就到这里了,第一次写博客,语言组织不太习惯,还请大家指点。