JQ第六部分源码学习
2019-07-22 本文已影响0人
没了提心吊胆的稗子
延迟对象 对异步的统一管理
// 整体框架
jQUery.extend({
Deferred: function(){},
when: function(){}
})
"resolve", "done"
"reject", "fail"
"notify", "progress"
一个action对应一个触发事件,前者对应的是callback里面的fire方法,后者对应的是add方法,成功失败都只能触发一次,但进行中可以触发多次
// ajax请求的改写
// 原来的方式
$ajax({
url: 'xxx',
success: function(){
alert('success');
}
error: function(){
alert('fail');
}
});
// 使用deferred延迟对象的方法 可以链式操作
// 成功resolve就触发done,失败reject就触发fail
$ajax('xxx').done(function(){ alert('success'); })
.fail(function(){ alert('fail'); });
如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。
// Deferred 延迟对象 对异步的统一管理
jQuery.extend({
Deferred: function( func ) {
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",
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 = 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();
},
// 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 = {};
// Keep pipe for back-compat
promise.pipe = promise.then;
// Add list-specific methods
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
// i ^ 1 i = 0的话结果就是1,反之0
}, 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;
});
// Make the deferred a promise
// 把promise的所有方法扩展到deferred上
promise.promise( deferred );
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
// Deferred helper
// 针对多延迟对象的操作 参数必须是Deferred对象
when: function( subordinate /* , ..., subordinateN */ ) {
// length存的要延迟的方法的数量,resolve完一个就length--
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
// the count of uncompleted subordinates
// 状态为改变为resolve的延迟对象的数量
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为0的时候就创建一个延迟对象 用来触发done回调函数
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 );
// 循环对传入的参数处理 是延迟对象就处理,不是就--remaining继续下一个
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();
}
});