jqueryソースのwhen

4363 ワード

$.when()は$です.Deferred()の補助方法.
一、whenの使い方.
whenは複数のDeferredオブジェクトをパラメータとして受け入れ、以下のいくつかのケースがあります.
1.インバウンドまたはインバウンドがいずれもDeferredオブジェクトでない場合、直接$を実行する.when().done()に追加された関数.
 $.when()
            .done(function(){
                alert("OK");
            })
            .fail(function(){
                alert("failed")   ;
            });
 var a , b, c;
    $.when(a,b,c)
            .done(function(){
                alert("OK");
            })
            .fail(function(){
                alert("failed")   ;
            });

2.1個のDeferredオブジェクトがパラメータとして使用する場合、Deferredオブジェクトが成功すると$が実行される.when().done()が追加したイベントは、失敗するとwhenのfailが追加した関数を実行します.
  var dfd1= $.Deferred();

    dfd1.done(function(){
        alert(1);
    });

    $.when()
            .done(function(){
                alert("OK");
            })
            .fail(function(){
                alert("failed")   ;
            });
    dfd1.resolve();

3.複数のDeferredオブジェクトがパラメータとして使用する場合、すべてのDeferredオブジェクトが正常に完了すると$がトリガーされる.when().done()に追加するイベントは、失敗すると$が実行される.when().fail()が追加したイベント.
  var dfd1= $.Deferred(),
            dfd2= $.Deferred();
    dfd1.done(function(){
        alert(1);
    });
    dfd2.done(function(){
        alert(2);
    });
    $.when(dfd1,dfd2)
            .done(function(){
                alert("OK");
            })
            .fail(function(){
                alert("failed");
            });
    dfd1.resolve();
    dfd2.reject();

二、ソースコード解析
(1)whenの中に1つしか入参していない場合
ソースコードの中に、内部のdeferredオブジェクトにパラメータが割り当てられていることを発見しました.このオブジェクトは$です.whenで作成され、返されます.この場合、中間のステップをスキップし、最後までreturn deferredに戻ります.promise()は、参照されたpromiseオブジェクトに戻り、doneイベントとfailイベントを追加します(同じdeferredオブジェクトに複数のdoneまたはfailを追加し、順番に実行できます).deferredオブジェクトのresolveを実行した後、doneに追加した関数を実行します.
(2)複数の入参がある場合、複数の入参がある場合、$.when()の内部には、$をコールバックするためのdeferredオブジェクトが作成されます.when().done().fail()に追加された関数.原理を見てみましょう.
<pre name="code" class="javascript">when: function( subordinate /* , ..., subordinateN */ ) {
		var i = 0,
			resolveValues = slice.call( arguments ),   // 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(),   //Deferred  ,            ,      ,   
  
 
  
 
 
 
      if ( length > 1 ) {      //  when        1 ,  if
			progressValues = new Array( length ); 
			progressContexts = new Array( length );
			resolveContexts = new Array( length );
			for ( ; i < length; i++ ) {
				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {  //Deferred     if
					resolveValues[ i ].promise()   //  deferred     done fail   
						.done( updateFunc( i, resolveContexts, resolveValues ) )  //  updateFunc
						.fail( deferred.reject )   //    fail      deferred   reject  
						.progress( updateFunc( i, progressContexts, progressValues ) );
				} else {
					--remaining;
				}
			}
		}

		// If we're not waiting on anything, resolve the master
		if ( !remaining ) {    //  remaining0,  if
			deferred.resolveWith( resolveContexts, resolveValues );  
		}

		return deferred.promise(); 

転送されたDeferredオブジェクトは、実行に成功した後、doneイベントのupdateFunc内部で返される匿名関数をコールバックし、その後--remaining、パラメータとしてのDeferredオブジェクトがすべて正常に実行され、remainingが0の場合、deferred.resolve()実行、コールバック$.when().done()が追加したコールバック.実行に失敗した場合、外部パラメータfailイベントがトリガーされ、内部deferredが実行されます.reject()では、$をコールバックする.when().fail()に追加されたコールバック
updateFunc = function( i, contexts, values ) {
				return function( value ) {
					contexts[ i ] = this;
					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
					if ( values === progressValues ) {
						deferred.notifyWith( contexts, values );
					} else if ( !( --remaining ) ) {
						deferred.resolveWith( contexts, values );
					}
				};
			},