zoukankan      html  css  js  c++  java
  • 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();
    	}
    

      

  • 相关阅读:
    2016年蓝桥杯B组C/C++决赛题解
    2016年蓝桥杯B组C/C++决赛题目
    线段树区间更新 费马小定理|魔豆传奇
    2015年蓝桥杯B组C/C++决赛题解
    欧拉线性筛 与 欧拉函数 + 几道例题
    2015年蓝桥杯B组C/C++决赛题目
    2017年蓝桥杯B组C/C++决赛题解
    2017年蓝桥杯B组C/C++决赛题目
    2019 蓝桥杯国赛 B 组模拟赛 题解
    2018年蓝桥杯B组C/C++决赛题解
  • 原文地址:https://www.cnblogs.com/hgonlywj/p/4862647.html
Copyright © 2011-2022 走看看