• jQuery-1.9.1源码分析系列(六) 延时对象续——辅助函数jQuery.when


      $.when的说明

      描述: 提供一种方法来执行一个或多个对象的回调函数,返回这些对象的延时(Deferred)对象。

      说明(结合实例和源码):

      如果你不传递任何参数,  jQuery.when()将返回一个resolved(解决)状态的promise对象。

      如果向jQuery.when()传入一个参数 , 并且它不是一个Deferred或Promise对象, 那么它会被当作是一个被解决(resolved)的延迟对象,并且绑定到上面的任何 doneCallbacks 都会被立刻执行。向 doneCallbacks 中传入的是原始的参数。在这种情况下,设定的任何 failCallbacks 永远都不会被执行,因为延迟对象永远不会被拒绝(rejected)。例如:

    $.when( { testing: 123 } ).done(
        function(x) { alert(x.testing); } /* alerts "123" */
    );

      上面两种情况,源码

           //如果没有传递参数或唯一一个参数且不是一个延时对象,直接解决主延时对象即可
           if ( !remaining ) {
                  deferred.resolveWith( resolveContexts, resolveValues );
           }

      如果向 jQuery.when() 传入一个单独的延迟对象,那么会返回它的 Promise 对象(延迟方法的一个子集)。可以继续绑定 Promise 对象的其它方法,例如, defered.then 。当延迟对象已经被解决(resolved)或被拒绝(rejected)(通常是由创建延迟对象的最初代码执行的),那么就会调用适当的回调函数。例如,由 jQuery.ajax() 返回的 jqXHR 对象是一并立的延迟对象并且可以像下面这样使用:

    $.when( $.ajax("test.aspx") ).then(function(data, textStatus, jqXHR){
         alert( jqXHR.status ); // alerts 200
    });

      源码

     return deferred.promise();

      在多个延迟对象传递给jQuery.when() 的情况下,该方法根据一个新的“宿主” Deferred(延迟)对象,跟踪所有已通过Deferreds聚集状态,返回一个Promise对象。当所有的延迟对象被解决(resolve)时,“宿主” Deferred(延迟)对象才会解决(resolved)该方法,源码

    //否则成员延时(Deferred)对象解决的时候才进入该分支判断
    //需要等待解决的延时(Deferred)对象数量减一,
    //判断还有没有需要等待解决的延时(Deferred)对象,如果有,则判断失败返回
    //如果没有则进入分支子代码,执行主延时(Deferred)对象解决deferred.resolveWith(...)
    else if ( !( --remaining ) ) {
      //最终执行到此步的时候values已经变成所有成员延时(Deferred)对象resolve的参数序列
      deferred.resolveWith( contexts, values );
    }

      或者当其中有一个延迟对象被拒绝(rejected)时,“宿主” Deferred(延迟)对象就会reject(拒绝)该方法,源码

    resolveValues[ i ].promise()
    .done( updateFunc( i, resolveContexts, resolveValues ) )
    //如果有一个成员延时(Deferred)对象拒绝时,则整个主延时(Deferred)对象直接拒绝
    .fail( deferred.reject )
    .progress( updateFunc( i, progressContexts, progressValues ) );

      如果“宿主” Deferred(延迟)对象是(resolved)解决状态时, “宿主” Deferred(延迟)对象的 doneCallbacks (解决回调)将被执行。参数传递给 doneCallbacks提供这解决(resolved)值给每个对应的Deferreds对象,并匹配Deferreds传递给 jQuery.when()的顺序。 例如:

    var d1 = $.Deferred();
    var d2 = $.Deferred();
     
    $.when( d1, d2 ).done(function ( v1, v2 ) {
        console.log( v1 ); // "Fish"
        console.log( v2 ); // "Pizza"
    });
     
    d1.resolve( "Fish" );
    d2.resolve( "Pizza" );

      

      在多延迟情况下,如果Deferreds延迟对象一被拒绝(rejected),jQuery.when()触发立即调用 “宿主” Deferred(延迟)对象的 failCallbacks。请注意在这个时间点上,有一些延迟对象仍然可以是未解决(unresolved)的。 传递给failCallbacks的参数匹配Deferred(延迟)对象的 failCallbacks被 rejected 拒绝的顺序。那么,在这种情况下,如果需要执行一些额外的处理,例如,取消所有未完成的 ajax 请求,你可以在闭包中进行保持 jqXHR 对象的引用,并且在 failCallback 中检查或取消它们。

      附上完整的源码

    // Deferred helper
    when: function( subordinate /* , ..., subordinateN */ ) {
        var i = 0,
            resolveValues = core_slice.call( arguments ),
            length = resolveValues.length, //参数个数
    
            //统计没有被解决的成员,
            //如果参数个数不为1,则remaining为参数个数,
            //如果参数个数为1且参数是 Deferred(延迟)对象则remaining为参数个数1;否则为0
            remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
    
            //初始化主延时对象,如果参数本身是一个延时对象则用参数即可,否则新建.
            deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
    
            // Update函数处理resolve和progress的值
            updateFunc = function( i, contexts, values ) {
                return function( value ) {
                    contexts[ i ] = this;
                    values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
                    //成员延时(Deferred)对象生成进度通知的时候主延时(Deferred)对象调用进行中的回调
             //后面代
    码.progress( updateFunc( i, progressContexts, progressValues),往进度回调列表添加函数的时候第三个参数就是progressValues        if( values === progressValues ) {
    //调用进行中的回调(progressCallbacks )
                        deferred.notifyWith( contexts, values );
    
                    //否则成员延时(Deferred)对象解决的时候才进入该分支判断
                    //需要等待解决的延时(Deferred)对象数量减一,
                    //判断还有没有需要等待解决的延时(Deferred)对象,如果有,则判断失败返回
                    //如果没有则进入分支子代码,执行主延时(Deferred)对象解决deferred.resolveWith(...)
                    } else if ( !( --remaining ) ) {
                        //最终执行到此步的时候values已经变成所有成员延时(Deferred)对象resolve的参数序列
                        deferred.resolveWith( contexts, values );
                    }
                };
            },
    
            progressValues, progressContexts, resolveContexts;
    
        //对于没有参数或是有唯一一个非延时对象的,直接认为resolved,也就是后面if ( !remaining ) 分支的处理
        //对于参数就是一个延时对象的直接将这个延时对象的deferred.promise()返回即可
        //对于参数多于一个的才进入该分支,添加监听器监听成员被解决
        if ( length > 1 ) {
            progressValues = new Array( length );
            progressContexts = new Array( length );
            resolveContexts = new Array( length );
            for ( ; i < length; i++ ) {
                //遍历参数成员,只有成员是延时(Deferred)对象的才需要监听器
                if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
                    resolveValues[ i ].promise()
                    .done( updateFunc( i, resolveContexts, resolveValues ) )
                    //如果有一个成员延时(Deferred)对象拒绝时,则整个主延时(Deferred)对象直接拒绝
                    .fail( deferred.reject )
                    .progress( updateFunc( i, progressContexts, progressValues ) );
    
                //非延时(Deferred)对象的直接认为已解决,需要等待解决的延时(Deferred)对象数量减一
                } else {
                    --remaining;
                }
            }
        }
    
        //如果没有传递参数或唯一一个参数且不是一个延时对象,直接解决主延时对象即可
        if ( !remaining ) {
            deferred.resolveWith( resolveContexts, resolveValues );
        }
    
        return deferred.promise();
    }
  • 相关阅读:
    shell脚本,文件里面的英文大小写替换方法。
    shell脚本,100以内的质数有哪些?
    shell脚本,当用sed删除某一文件里面的内容时,并追加到同一个文件会出现问题。
    shell脚本,按行读取文件的几种方法。
    shell脚本,锁机制
    shell脚本,通过一个shell程序计算n的阶乘。
    shell脚本,如何写进度条。
    shell脚本,判断给出的字符串是否相等。
    shell脚本,按空格开始60秒的倒计时。
    18:django 日志系统
  • 原文地址:https://www.cnblogs.com/chuaWeb/p/jQuery-1-9-1-Deferred2.html
Copyright © 2020-2023  润新知