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

相關文章
相關標籤/搜索