jquery中的 deferred之 when (三)

先来看使用案例:promise

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中最后执行,有一段核心代码this

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

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

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

经过这个思路咱们能够简化个案例,获得这个全部人都要度过河的案例:对象

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:渡河成功!
            //全部人员都渡河成功!

在咱们实际工做中这个思路很重要。blog

相关文章
相关标签/搜索