首先来一张jQuery.Deferred的结构图:
再来一张执行deferred.then(/*fnDone, fnFail, fnProcess*/)后的结构图:
最后来看看源代码:
1 jQuery.extend({
2
3 Deferred: function( func ) {
4 // 数据元组集
5 // 每个元组分别包含一些与当前deferred相关的信息:
6 // 分别是:触发回调函数列表执行(函数名),添加回调函数(函数名),回调函数列表(jQuery.Callbacks对象),deferred最终状态(第三组数据除外)
7 // 总体而言,三个元组会有对应的三个callbacklist对应于doneList, failList, processList
8 // 对于jQuery.Callbacks对象,可以看之前的文章
9 var tuples = [
10 // action, add listener, listener list, final state
11 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
12 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
13 [ "notify", "progress", jQuery.Callbacks("memory") ]
14 ],
15 // deferred的状态,分为三种:pending(初始状态), resolved(解决状态), rejected(拒绝状态)
16 state = "pending",
17 // promise对象,主要有两点作用:
18 // 1. 在初始化deferred对象时,promise对象里的方法都会被extend到deferred中去,作为引用(见86行)
19 // 2. 那么,生成的deferred对象里必然引用了promise对象的promise方法,所以当调用deferred.promise()时,
20 // deferred对象会通过闭包返回promise对象,这就是所谓的受限制的deferred对象(用deferred2表示),因为相比之前,
21 // 返回的deferred2不在拥有resolve(With), reject(With), notify(With)这些能改变deferred对象状态并且执行callbacklist的方法了
22 promise = {
23 // 返回闭包里的内部state(外部只读)
24 state: function() {
25 return state;
26 },
27 // 同时在doneList和failList的list里添加回调函数(引用)
28 // 那么不论deferred最终状态是resolved还是rejected, 回调函数都会被执行,这就是所谓的always
29 always: function() {
30 deferred.done( arguments ).fail( arguments );
31 return this;
32 },
33 // jQuery.then()会创建一个新的受限制的deferred对象
34 // 有点复杂,下面我有画一个图帮忙理解
35 then: function( /* fnDone, fnFail, fnProgress */ ) {
36 var fns = arguments;
37 // 创建新的受限制的deferred对象(称作newDeferrred),并返回
38 // 利用返回的deferred对象就可以做很多事了,你懂的
39 return jQuery.Deferred(function( newDefer ) {
40 jQuery.each( tuples, function( i, tuple ) {
41 var action = tuple[ 0 ],
42 fn = fns[ i ];
43 // deferred[ done | fail | progress ] for forwarding actions to newDefer
44 // 分别为deferred的三个callbacklist添加回调函数,根据fn的是否是函数,分为两种情况:
45 // 1.不是函数的情况(如值为undefined或者null等),直接链接到newDeferred的resolve(reject,notify)方法,也就是说
46 // newDeferrred的执行依赖外层的调用者deferred的状态或者说是执行动作(resolve还是reject或者是notify)
47 // 此时deferred.then()相当于将自己的callbacklist和newDeferred的callbacklist连接起来了,故可以在newDeferred
48 // 中大做文章
49 // 2.是函数的情况,根据返回值(称作returnReferred)是否是deferred对象,又可以分为两种情况:
50 // 2.1 返回值是deferred对象,那么在returnReferred对象的三个回调函数列表中添加newDeferred的resolve(reject,notify)方法
51 // 也就是说newDeferrred的执行依赖returnDeferred的状态
52 // 2.2 返回值不是deferred对象,那么将返回值returned作为newDeferred的参数并将从外层deferred那边的上下文环境作为newDeferred
53 // 的执行上下文,然后执行对应的回调函数列表,此时newDeferrred的执行依赖外层的调用者deferred的状态
54 deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
55 function() {
56 var returned = fn.apply( this, arguments );
57 if ( returned && jQuery.isFunction( returned.promise ) ) {
58 returned.promise()
59 .done( newDefer.resolve )
60 .fail( newDefer.reject )
61 .progress( newDefer.notify );
62 } else {
63 newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
64 }
65 } :
66 newDefer[ action ]
67 );
68 });
69 fns = null;
70 }).promise();
71 },
72 // Get a promise for this deferred
73 // If obj is provided, the promise aspect is added to the object
74 promise: function( obj ) {
75 return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise;
76 }
77 },
78 // 实际返回的deferred对象
79 deferred = {};
80
81 // Keep pipe for back-compat
82 // pipe和then引用同一个函数,所以功能是一样的
83 // 只不过通常的用法是:会用pipe进行filter操作
84 promise.pipe = promise.then;
85
86 // Add list-specific methods
87 // 通过上面定义的数据元组集来扩展一些方法
88 jQuery.each( tuples, function( i, tuple ) {
89 var list = tuple[ 2 ],
90 stateString = tuple[ 3 ];
91
92 // promise[ done | fail | progress ] = list.add
93 // 给上面的promise对象添加done,fail,process方法
94 // 这三个方法分别引用三个不同jQuery.Callbacks对象的add方法(不是同一个引用),
95 // 那么这三个方法的用途就是向各自的回调函数列表list(各自闭包中)中添加回调函数,互不干扰
96 promise[ tuple[1] ] = list.add;
97
98 // Handle state
99 // 通过stateString有值这个条件,预先向doneList,failList中的list添加三个回调函数
100 // doneList : [changeState, failList.disable, processList.lock]
101 // failList : [changeState, doneList.disable, processList.lock]
102 // changeState 指的是下面首先添加的一个改变deferred对象的匿名函数
103 // 可以看的出: 不论deferred对象最终是resolve(还是reject),在首先改变对象状态之后,都会disable另一个函数列表failList(或者doneList)
104 // 然后lock processList保持其状态,最后执行剩下的之前done(或者fail)进来的回调函数
105 // 当然了,上述情况processList除外
106 if ( stateString ) {
107 list.add(function() {
108 // state = [ resolved | rejected ]
109 state = stateString;
110
111 // [ reject_list | resolve_list ].disable; progress_list.lock
112 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
113 }
114
115 // deferred[ resolve | reject | notify ] = list.fire
116 // 给deferred对象添加resolve(With), reject(With), notify(With)方法
117 // 这三个方法分别引用三个不同jQuery.Callbacks对象的fire方法(不是同一个引用),
118 // 那么这三个方法的用途就是执行各自的回调函数列表,互不干扰
119 deferred[ tuple[0] ] = list.fire;
120 deferred[ tuple[0] + "With" ] = list.fireWith;
121 });
122
123 // Make the deferred a promise
124 // 将上面的promise对象extend进deferred中
125 promise.promise( deferred );
126
127 // Call given func if any
128 // 如果调用jQuery.Deferred(func)指定了参数,那么调用func并设置func的上下文和参数均为deferred
129 // 在jQuery.then()中有用到这一点
130 if ( func ) {
131 func.call( deferred, deferred );
132 }
133
134 // All done!
135 // 返回最终的deferred对象
136 return deferred;
137 },
138
139 // Deferred helper
140 // 参数:一个(或多个)deferred对象(或其他)
141 // 当传入的所有deferred对象都resolve或者reject了,执行when()创建的deferred对象(称之为whenDeferred)对应的回调函数列表(非deferred对象被认为是resolve了)
142 when: function( subordinate /* , ..., subordinateN */ ) {
143 var i = 0,
144 // 首先将arguments伪数组转换为真正的数组
145 resolveValues = core_slice.call( arguments ),
146 length = resolveValues.length,
147
148 // the count of uncompleted subordinates
149 // jQuery.isFunction( subordinate.promise )用来判断subordinate是否是deferred对象
150 // 1. 在参数个数等于1的情况下:
151 // 1.1 如果参数是deferred对象,那么remaining = length, 这是remaining就是1嘛
152 // 1.2 否则remaining为0
153 // 2. 在参数不等于1(即等于0或者大于1)的情况:remaining = length
154 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
155
156 // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
157 // 到这里就可以知道:如果参数个数仅为1个,并且是deferred对象,那么就无需再生成deferred对象
158 deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
159
160 // Update function for both resolve and progress values
161 updateFunc = function( i, contexts, values ) {
162 // 这里返回一个函数作为一个callback完全是为了创建一个闭包,主要是为了保持i的值
163 return function( value ) {
164 // 保存各个deferred执行的上下文,也就是说之后whenDeferred的回调函数的上下文就是一个数组
165 contexts[ i ] = this;
166 // 保存各个deferred执行时的参数,之后传递给whenDeferred的回调函数
167 // 此时values的值有原先的jQuery.when()传进来的参数变为各个deferred执行回调时的参数了,也就是说覆盖了
168 values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
169 if( values === progressValues ) {
170 // 这里,暂时不理解有什么用处?
171 deferred.notifyWith( contexts, values );
172 } else if ( !( --remaining ) ) {
173 // 时机成熟,即所有延迟都resolve,执行whenDeferred的回调函数
174 deferred.resolveWith( contexts, values );
175 }
176 };
177 },
178
179 progressValues, progressContexts, resolveContexts;
180
181 // add listeners to Deferred subordinates; treat others as resolved
182 // 如果参数个数大于1,那么就是说有可能存在多个deferred对象
183 // 这时需要一些条件判断以保证是所有的deferred对象都resolve了,再执行whenDeferred的resolve
184 // 或者当有一个deferred对象reject了,whenDeferred的reject
185 if ( length > 1 ) {
186 progressValues = new Array( length );
187 progressContexts = new Array( length );
188 resolveContexts = new Array( length );
189 for ( ; i < length; i++ ) {
190 // 如果是deferred对象
191 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
192 // 给每个参数(deferred对象)添加最后的回调,用来检查此时的状态
193
194 resolveValues[ i ].promise()
195 // 用于当每一个deferred对象resolve回来,用updateFunc返回的函数检查此时其他deferred对象的状态(即此时remaining是否等于0了)
196 // 如果等于0,则执行whenDeferred的resolve,否则继续等待
197 .done( updateFunc( i, resolveContexts, resolveValues ) )
198 // 如果有一个deferred对象reject,whenDeferred将执行reject
199 .fail( deferred.reject )
200 // 用于通知,暂时不知道有什么用?
201 .progress( updateFunc( i, progressContexts, progressValues ) );
202 // 如果不是deferred对象,直接--remaining,视为resolve
203 } else {
204 --remaining;
205 }
206 }
207 }
208
209 // if we're not waiting on anything, resolve the master
210 // 如果此时remaining就等与0了,表示没有什么延迟需要等待,那么立即之行whenDeferred的resolveWith
211 // 此时resolveContexts为undefined, 这就意味这上下文将为全局的window
212 if ( !remaining ) {
213 deferred.resolveWith( resolveContexts, resolveValues );
214 }
215
216 // 返回受限制的deferred对象
217 return deferred.promise();
218 }
219 });