jQuery-v2.0.3ソース浅い分析05-when

3287 ワード

jQueryが提供するwhenメソッドは、複数のDeferredオブジェクトを管理できます.たとえば、複数のDeferredオブジェクトを作成した場合、すべてのDeferred呼び出しが完了した後にコードを実行したい場合は、whenを使用して実現できます.
ソースコード
/**  3089 **/
when: function( subordinate /* , ..., subordinateN */ ) {
    var i = 0,
        resolveValues = core_slice.call( arguments ),
        length = resolveValues.length,

        /**  3095 **/
        remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,

        /**  3098 **/
        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;

    /**  3116 **/
    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;
            }
        }
    }

    /**  3133 **/
    if ( !remaining ) {
        deferred.resolveWith( resolveContexts, resolveValues );
    }

    return deferred.promise();
}

げんり
whenの原理:remainingを利用してDeferredの数を記録し、伝達されたものがDeferredオブジェクトでない場合は記録しない(ソースコードで直接remaining-1操作を行う).Deferredが正常に実行されるとremainingは-1操作され、最後のDeferredが正常に実行されると(remainingが0に等しい場合)whenメソッドで作成されたDeferredオブジェクトがトリガーされます.いずれかのDeferred呼び出しに失敗したメソッドが発生した場合は、whenのrejectを直接呼び出します.入力されたパラメータがDeferredオブジェクトでない場合は、コールバック関数が直接呼び出されます.
説明する
まず、ソース3095行とソース3098行を見てみましょう.ここでは、入力されたパラメータが1つしかなく、Deferredオブジェクトである場合、このDeferredオブジェクトを直接使用し、入力されたパラメータがDeferredオブジェクトでない場合、または複数のパラメータが存在する場合、新しいDeferredオブジェクトを直接作成することを意味します.
ソースコード3116行は、パラメータの個数が1個より大きい場合、まずこれらのパラメータをループしてDeferredオブジェクトかどうかを判断し、そうでなければremainingを直接-1操作し、DeferredオブジェクトであればdoneとprogressがupdateFunc関数を呼び出しているのを見ることができる.3番目のパラメータがprogressValuesであれば、作成したdeferredのnotifyWithを直接呼び出すので、whenの後ろにバインドされたprogressは、パラメータのDeferredオブジェクトに基づいてprogressを呼び出す回数を複数回トリガーする可能性があります.doneがトリガするupdateFuncメソッドの場合、この場合はまずremainingを-1操作し、remainingが0に等しい場合はdeferredのresolveWithを直接トリガします.
ソース3133行は,我々が入力したパラメータがすべてDeferredオブジェクトでなければ,このとき我々が直接成功をトリガする方法を意味する.最後にpromise();ステータスを変更する方法は外部に提供されません.
使用法
var def1 = $.Deferred();
setTimeout(function(){
    def1.resolve();
}, 1000);

$.when(def1).done(function(){
    console.log('    ');
}).fail(function(){
    console.log('   ');
})
//1