jQuery中延迟对象then方法和when方法源码分析

每个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();
	}

猜你喜欢

转载自blog.csdn.net/Night_Emperor/article/details/78174509
今日推荐