每个then()函数都会返回一个新的deferred对象,then方法先根据父级状态执行添加的函数,然后再根据情况修改状态。
在父级的deferred对象的三个添加函数done fail progress中,都添加了一个相同的函数。
如果函数的执行结果返回的也是一个deferred对象,则then方法返回的deferred对象对象的状态取决于函数返回的deferred对象。
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 );
}
}
then()
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
//then方法添加的函数的执行依赖于父级延迟对象的状态,子级对象的状态,根据不同情况进行判断
deferred[ tuple[1] ](function() {
var returned = fn && fn.apply( this, arguments );
//如果then方法添加的函数有返回值并且是延迟对象,则该延迟对象决定子级延迟对象的状态
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
// then方法添加的函数没有返回值,或返回值不是延迟对象,子级状态跟父级保持一致
// then方法添加的函数有返回值,不是延迟对象,返回值作为下一个then方法添加函数的参数
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
});
fns = null;
}).promise();
var aaa = function(){
var f = $.Deferred();
f.reject();
f.fail(function(){
alert('222');
})
// return f;
};
var bbb = function(){
var e = $.Deferred();
e.reject();
e.fail(function(){
alert('333');
})
return e;
};
var d = $.Deferred();
d.resolve();
d.done(function(){
alert('111')
});
var t = d.then(aaa,bbb);
t.then(function(){
alert('555');
},function(){
alert('666');
});
结果是依次弹出111,222,555;如果aaa函数返回一个延迟对象,并且状态是reject,则依次弹出111,222,666
var val=1
var d = $.Deferred();
d.resolve(val);
d.done(function(val){
alert(val);//1
}).then(function(val){
return 2*val
}).then(function(val){
alert(val);//2
});
var val=1
var d = $.Deferred();
d.resolve(val);
d.done(function(val){
alert(val);//1
}).then(function(val){
alert(val);//1
}).then(function(val){
alert(val);//undefined
});
第一个then方法添加的函数的参数和父级的相同:
deferred[ tuple[1] ](function() {
var returned = fn && fn.apply( this, arguments );
...
}
从第二个then开始,添加函数的参数由上个then方法添加的函数的返回值决定,如果返回一个延迟对象,则参数由返回延迟对象的参数决定: fn ? [ returned ] : arguments。也可以这样理解每一个then添加的函数的参数,都是上一个函数的返回值(返回值时deferred对象除外),但是第一个then前面没有then,第一个then添加函数的参数只能和父级相同。
var val=1
var d = $.Deferred();
d.resolve(val);
d.then(function(val){
var call = $.Deferred();
call.resolve('a');
call.done(function(val){
alert(val);//a
})
return call;
}).then(function(val){
alert(val);//a
});
原因是:返回的延迟对象,通过“add”,添加了子级延迟对象的状态函数,参数也会相应传递
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
}
从第二个then开始,添加函数的参数由上个then方法添加的函数的返回值决定,如果返回的不是延迟对象,则返回值直接作为参数。
var val=1
var d = $.Deferred();
d.resolve(val);
d.then(function(val){
alert(val);//1
return 100;
}).then(function(val){
alert(val);//100
});
原因:
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
怎么理解$.when(),$.when()返回的是promise对象,即无法修改状态,只能添加回调函数,
因为状态是由参数中的延迟对象的状态共同决定的,
1.当没有参数时,remaining=0,创建延迟对象,直接调用deferred.resolveWith
2.只有一个参数时,并且不是延迟对象,创建延迟对象,直接调用deferred.resolveWith
3.只有一个参数,并且是延迟对象,返回该延迟对象的deferred.promise()
4.多个延迟对象并存,只要有一个reject,返回新对象的状态为reject
5.多个延迟对象并存,没有一个reject,只要有一个process,返回对象的状态为notify
6.存在的延迟对象都是resolve时,调用deferred.resolveWith
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();
}