jQuery 源码: 延迟对象补充。

// Deferred helper (3132)
when 是延迟对象 Deferred的一个辅助方法。

 

    var dfd = $.Deferred();        //创建延迟对象
    dfd。done();
    dfd.fail();

    //使用:
    $.when().done();
    $.when().fail();

 

when的返回值,是一个延迟对象。
  源码: return deferred.promise();

 

举个例子:when可以等待多个延迟对象都成功后,触发成功。
例子:(1)

 

成功必须多个都成功。
	function aaa() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('aaa');
			dfd.resolve();
		}, 1000);


		return dfd;
	}

	function bbb() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('bbb');
			dfd.resolve();
		}, 2000);

		return dfd;
	}

	$.when(aaa(), bbb()).done(function () {
		alert('done');
	});
//	目标是aaa和bbb都完成以后,才触发这个成功。
//	只有一个延迟对象成功,不会判定是否成功。
//	这里就是等aaa 和 bbb都完成以后。才执行done函数。

 

例子:(2)
失败触发,只要一个失败就可以。而且失败的时候,就立即触发回调函数。

    function aaa() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('aaa');
			dfd.reject();
		}, 1000);


		return dfd;
	}

	function bbb() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('bbb');
			dfd.resolve();
		}, 2000);

		return dfd;
	}



	$.when(aaa(), bbb()).fail(function () {
		alert('fail');
	});

 // 目标是aaa和bbb有一个失败,就立刻出发失败这个函数。

 

 


这里的argus是参数,很多个延迟对象的代表的状态。
$.when(argus).done(function() {
  alert('done');
}).fail(function () {
  alert('fail');
});

argus[i] 对应着每一个延迟对象,jQuery有计数器。来计算所有argus的状态。
只要满足了条件,就可以触发说对应的事件。

比如传入三个参数:
$.when(A, B, C).done(function() {
  alert('done');
}).fail(function () {
  alert('fail');
});

那么代码中就会产生一个计数器。来判断这个三个延迟对象是否已经完成,
如果完成一个,就-1,当计数器为0的时候,触发成功。
当然,如果有一个延迟对象失败了,就直接触发失败的回调函数。

 

 

例子(3)
	function aaa() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('aaa');
			// dfd.reject();
		}, 1000);


		return dfd;
	}

	function bbb() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('bbb');
			dfd.resolve();
		}, 2000);

		return dfd;
	}

	$.when(aaa(), bbb()).done(function() {
		alert('done');
	}).fail(function () {
		alert('fail');
	});

注意:执行结果是 打印 aaa bbb ,但是不会触发事件,因为aaa()对象中,一直没有触发延迟对象的状态改变。
所以,when就只能等待。

 

 

例子(4)
	function aaa() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('aaa');
			// dfd.reject();
		}, 1000);


		return dfd;
	}

	function bbb() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('bbb');
			dfd.resolve();
		}, 2000);

		return dfd;
	}

	$.when(aaa(), bbb()).done(function() {
		alert('done');
	}).fail(function () {
		alert('fail');
	});

 

测试结果是:打印 aaa bbb, 然后弹出done。
为什么呢?状态都完成了,但是aaa没有返回。导致,aaa()中的reject,就没有起作用。
因为在, $.when() 中传入的是延迟对象,但是函数没有返回值,也就没有延迟对象的传入,
因此,aaa(), 这个参数,就没办法起到作用了。就跳过去了。因为bbb(),完成了,就导致触发成功。

 

例子(5)

A:状态
	$.when().done(function() {
		alert('done');
	}).fail(function () {
		alert('fail');
	});


B:状态
	
	$.when(123, 1234).done(function() {
		alert('done');
	}).fail(function () {
		alert('fail');
	});

 

A状态和B状态都是直接触发成功的。
当$.when(argus)中的参数argus不是延迟对象,就直接跳过,就相当于没写。

 

 

例子(6)

	function aaa() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('aaa');
			dfd.reject();
		}, 1000);

		// return dfd;
	}

	function bbb() {
		var dfd = $.Deferred();		//创建延迟对象
		setTimeout(function () {
			console.log('bbb');
			dfd.resolve();
		}, 2000);

		return dfd;
	}

	$.when(aaa(), bbb(), 123).done(function() {
		alert('done');
		alert(arguments[2]);
	}).fail(function () {
		alert('fail');
		alert(arguments[2]);
	});

     //这里的 arguments[0]是123, arguments[1]是1234.
	$.when(123, 1234).done(function() {
		alert('done');
	}).fail(function () {
		alert('fail');
	});

 

例子(7) 

	$.when(aaa(), 123, bbb(). 345).done(function() {
		alert('done');
		alert(arguments[1]);
		alert(arguments[3]);

	}).fail(function () {
		alert('fail');
		alert(arguments[1]);
		alert(arguments[3]);

	}); 

这里传入了4个参数,但是只有2个是延迟对象, 因此,需要判断并更新,--remaining操作,将不是延迟对象的去掉。


总结一下思想:首先判读传入的参数,有几个延迟对象,如果一个没有,就直接执行done。自执行done,fail是不会执行的。
如果有,就检测执行,判断计数器是否为0了,并且是成功的返回(resolve),为0了就执行对应的成功函数,
如果有一个是失败的(reject),OK,那就是直接调用fail就好了。

 

when 源码:
	// Deferred helper
	when: function( subordinate /* , ..., subordinateN */ ) {
			var i = 0,
			//将arguments---》》》转换为数组。
			resolveValues = core_slice.call( arguments ),
			length = resolveValues.length,

			// the count of uncompleted subordinates
			//  (1)	这个就是计数器,判断是否还有未完成的情况
			//	(2)	如果是传入的是空的, 返回0,如果是正常的延迟对象,就返回length。
			// 	jQuery.isFunction( subordinate.promise ), 判断传入的是不是一个延迟对象。

			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 ) ) {	//	这里减到0,就触发。
						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++ ) {
				// 判断一下是否是延迟对象。
				// resolveValues 这个就是之前处理传入参数,返回的数组。

				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
					resolveValues[ i ].promise()
						.done( updateFunc( i, resolveContexts, resolveValues ) )	//这里还需要判断,计数器是否 到了0.
						.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();
	}

  

原文地址:https://www.cnblogs.com/hgonlywj/p/4862647.html