• jquery中的 deferred之 when (三)


    先来看使用案例:

    var def1 = $.Deferred();
                var def2 = $.Deferred();
                var def3 = $.Deferred();
                var def4 = $.Deferred();
    
                var fun1 = function (def) {
                    setTimeout(function () {
                        console.log("fun1 resolve");
                        def.resolve();
                    }, 3000);
                    return def;
                };
                var fun2 = function (def) {
                    setTimeout(function () {
                        console.log("fun2 resolve");
                        def.resolve();
                    }, 2000);
                    return def;
                };
                var fun3 = function (def) {
                    setTimeout(function () {
                        console.log("fun3 resolve");
                        def.resolve();
                    }, 1000);
                    return def;
                };
                var fun4 = function (def) {
                    setTimeout(function () {
                        console.log("fun4 resolve");
                        def.resolve();
                    }, 1000);
                    return def;
                };
                $.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4)).done(function () {
                    console.log("并行执行完毕");
                });
                //执行结果:
                //fun3 resolve
                //fun4 resolve
                //fun2 resolve
                //fun1 resolve
                //并行执行完毕

    执行的过程如下:

    源码分析:

    // Deferred helper
        when: function( subordinate /* , ..., subordinateN */ ) {
            var i = 0,
                resolveValues = core_slice.call( 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.
                //20170620 huanhua 这就是 when里面的参数 subordinate必须是返回 deferred对象的函数的原因。
                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;
                        //20170624 huanhua 在 progess 中时 ,传递的 values 就是 progressValues ,所以 此时 values === progressValues 是成立的,触发 deferred.notifyWith
                        if( values === progressValues ) {
                            deferred.notifyWith(contexts, values);
                        //20170624 huanhua 在 done 时,传递的 values 就是 resolveValues ,所以 此时 values === progressValues 是不成立的,
                        //在 remaining = 0,全部都执行完了 ,触发 deferred.resolveWith( contexts, values );
                        } else if ( !( --remaining ) ) {
                            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++) {
                    //20170624 huanhua 判断传入的个参数是否是 deferred 对象
                    //如果是
                    if (resolveValues[i] && jQuery.isFunction(resolveValues[i].promise)) {
                        //20170625 huanhua 给  when()参数中的各个对象注册方法
                        resolveValues[ i ].promise()
                            .done( updateFunc( i, resolveContexts, resolveValues ) )
                            .fail( deferred.reject )
                            .progress(updateFunc(i, progressContexts, progressValues));
                     //如果不是
                    } else {
                        --remaining;
                    }
                }
            }
    
            // if we're not waiting on anything, resolve the master
            //20170624 huanhua 如果一个都没参数都没传递,就直接执行 
            if ( !remaining ) {
                deferred.resolveWith( resolveContexts, resolveValues );
            }
            return deferred.promise();
        }

     $.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4))返回的就是一个 Deferred.promise对象.

    updateFunc = function( i, contexts, values ) {
                    return function (value) {
                        contexts[ i ] = this;
                        values[i] = arguments.length > 1 ? core_slice.call(arguments) : value;
                        //20170624 huanhua 在 progess 中时 ,传递的 values 就是 progressValues ,所以 此时 values === progressValues 是成立的,触发 deferred.notifyWith
                        if( values === progressValues ) {
                            deferred.notifyWith(contexts, values);
                        //20170624 huanhua 在 done 时,传递的 values 就是 resolveValues ,所以 此时 values === progressValues 是不成立的,
                        //在 remaining = 0,全部都执行完了 ,触发 deferred.resolveWith( contexts, values );
                        } else if ( !( --remaining ) ) {
                            deferred.resolveWith( contexts, values );
                        }
                    };
                },

     $.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4))中,fun1(def1)给这个的返回结果def1注册 done(),并且此时给def1.done()注册的方法是在 done中最后执行,有一段核心代码

    //在 remaining = 0,全部都执行完了 ,触发 deferred.resolveWith( contexts, values );
                        } else if ( !( --remaining ) ) {
                            deferred.resolveWith( contexts, values );
                        }

    remaining闭包when的参数个数,当所有的参数都执行完了的时候,就调用 

     $.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4))中的对象 deferred.resolveWith().

    通过这个思路我们可以简化个案例,得到这个所有人都要度过河的案例:

    var Person = function (name) {
                    var name = name;
                    var listDo = [];
                    this.do = function (fn) {
                        listDo.push(fn);
                    };
                    this.fire = function () {
                        for (var xh in listDo) {
                            listDo[xh](name);
                        }
                    };
                };
    
                var Duhe = function (person1, person2, person3, person4) {
                    var listDo = [];
                    var length = arguments.length;
                    var that = this;
                    var interval = [3000,2000,2500,1000];
                    for (var arg in arguments) {
                        arguments[arg].do(function (name) {
                            setTimeout(function () {
                                console.log(name + ":渡河成功!");
                                if (!(--length)) {
                                    that.fire();
                                }
                            }, interval[arg]);
                        });
    
                    };
                    for (var arg in arguments) {
                        arguments[arg].fire();
                    };
                    this.do = function (fn) {
                        listDo.push(fn);
                        return this;
                    };
                    this.fire = function () {
                        for(var xh in listDo){
                            listDo[xh]();
                        }
                    };
                }
                var duhe = new Duhe(new Person("Person1"), new Person("Person2"), new Person("Person3"), new Person("Person4"), new Person("Person5"));
                duhe.do(function () { console.log("所有人员都渡河成功!"); });
                //答案:
                //Person5:渡河成功!
                //Person4:渡河成功!
                //Person2:渡河成功!
                //Person3:渡河成功!
                //Person1:渡河成功!
                //所有人员都渡河成功!

    在我们实际工作中这个思路很重要。

  • 相关阅读:
    Python股票分析系列——系列介绍和获取股票数据.p1
    快速相关
    特别长序列的快速卷积
    长序列的快速卷积
    快速卷积
    素因子快速傅里叶变换
    用一个N点复序列的FFT同时计算两个N点实序列离散傅里叶变换
    实序列快速傅里叶变换(二)
    实序列快速傅里叶变换(一)
    java 对于手机号码、邮箱、银行卡号脱敏一条龙服务
  • 原文地址:https://www.cnblogs.com/huaan011/p/7074438.html
Copyright © 2020-2023  润新知