jquery deferred对象解析
建议先看下callbacks对象的实现
Deferred 是callbacks 方法的封装调用。开启三个队列实例,分别是resolve,reject,notify。将每个队列开启list.add方法,并且分别指向自己的done、fail、progress
。
触发 resolve,reject方法,实际上指向的是callbacks的 fireWith方法,直接触发了队列。所以先使用then方法,加入队列中,然后使用resolve, reject来进行队列的触发,关闭等操作~
简单调用方法
var d = new Deferred();
d.then(function(
console.info('resolve done');
),function(){
console.info('reject fail');
},funciton() {
console.info('notify progress);
});
// ====不能同时触发===可以单个执行===
// 直接触发done
d.resolve();
// fail
d.reject();
// pregress
d.notify();
deferred的中文注解
jQuery.extend({
Deferred: function( func ) {
var tuples = [
// once more 保证添加到队列的,只执行一次,并且一旦add立即触发
// 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",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
// jQuery.Defered(func()).promise();
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
// resolve/reject/notify
var action = tuple[ 0 ],
// 如果没有fnsi 那么久违undefined
fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
// deferred['done']() | deferred['fail']() |deferred['progress']() 在下面有定义
// 实际上这里的deferred done 指向的是list.add,将done,fail,progress的方法都进行了队列添加
deferred[ tuple[1] ](function() {
// 直接调用fn方法,得到返回结果(这个returned是deferred对象么?为什么可以调用returned.promise)
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
// 将方法扩展到deferred对象实例,然后执行done,fail,progress方法
// 实际上是进行了callbacks的add调用,不过进行了区分顺序
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();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
// 将promise和obj进行合并
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
// Keep pipe for back-compat
promise.pipe = promise.then;
// Add list-specific methods
// 建立resolve,reject,notify的队列实例,并且对done,fail,progress指向list.add 使其可以对自己的队列进行添加方法
jQuery.each( tuples, function( i, tuple ) {
// 队列实例
var list = tuple[ 2 ],
stateString = tuple[ 3 ];
// promise[ done | fail | progress ] = list.add
// 将队列实例的add方法赋值给promise的 resolve/reject/notify
// 引用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
// 执行了异或运算,将列表置为disable,将最后的notify lock
// 0 ^ 1 = 1
// 1 ^ 1 = 0
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
// deferred[ resolve | reject | notify ]
// 组装deferred对象 添加 resolve,reject,notify属性方法
deferred[ tuple[0] ] = function() {
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
// 组装deferred对象 添加resolveWith,rejectWith,notifyWith对象指向callbacks的FireWire方法
// fireWith 是用来拼接list的方法~
deferred[ tuple[0] + "With" ] = list.fireWith;
});
// Make the deferred a promise
// 组装deferred对象 将promise合并到deferred
promise.promise( deferred );
// Call given func if any
// 直接调用该方法~
if ( func ) {
func.call( deferred, deferred );
}
// All done!
// deferred 对象包含了 resolve,reject,notify,resolveWith,rejectWith,notifyWith,pipe,done,fail,progress,state,always,then,promise
return deferred;
},
// Deferred helper
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();
}
});