jquery Deferred 延迟对象的读书笔记-源码分析

Deferred:延迟对象,对异步的统一管理

基本使用

Deferred延迟对象是基于Callbacks对象的,因此要先熟悉Callbacksjquery

Deferred提供方法链的形式进行函数的封装数组

DeferredDeferred做为jquery的工具方法,封装了3中状态promise

1.已完成闭包

var dfd = $.Deferred();
setTimeout(function () {
    console.log("set time out");
    dfd.resolve();//控制台输出success
},1000);

dfd.done(function () {
    console.log("success");
}).fail(function () {
    console.log("fail");
}).progress(function () {
    console.log("progress");
});

2.未完成app

var dfd = $.Deferred();
setTimeout(function () {
    console.log("set time out");
    dfd.reject();//控制台输出fail
},1000);

dfd.done(function () {
    console.log("success");
}).fail(function () {
    console.log("fail");
}).progress(function () {
    console.log("progress");
});

3.进行中异步

var dfd = $.Deferred();
setInterval(function () {
    console.log("set time out");
    dfd.notify();//控制台1s间隔输出progress
},1000);

dfd.done(function () {
    console.log("success");
}).fail(function () {
    console.log("fail");
}).progress(function () {
    console.log("progress");
});

 

Deferred(func)参数

参数说明:ide

1.func将做为异步函数传入Deferred对象,并立刻进行调用函数

var dfd = $.Deferred(
    function () {
        alert(111);//控制台弹出111
    }
);

参数处理:工具

if ( func ) {
    //Deferred中判断有参数传入后进行立刻调用,并将自身对象传入改函数
    func.call( deferred, deferred );
}

 

Deferred的私有成员

1.tuples[][]:保存Deferred须要使用的数组源码分析

2.state:临时Deferred的状态变量,缺省为pending

3.promise{}:保存Deferred的私有方法

4.deferred{}:保存Deferred的公有方法

 

关于promise与deferred的具体区别:

1.deferred将做为Deferred建立时的返回值,而promise将只在Deferred内部使用

2.promise具备成员:

promise = {
    state:function,
    alaways:function,
    then:function,
    promise:function,
    pipe:function,
    done:function,
    fail:function,
    progress:function,
}

3.deferred具备成员:

deferred = {
    state:function,
    alaways:function,
    then:function,
    promise:function,
    pipe:function,
    done:function,
    fail:function,
    progress:function,
    
    resolve:function,
    reject:function,
    notify:function,
}

4.deferred的具备的成员比promise的多一些,利用这一特性,能够作一些有用的事,

如:禁止修改状态值

function test() {
    var dfd = $.Deferred();
    setTimeout(function () {
        dfd.resolve();
        alert(dfd.state());
    }, 1000);
    return dfd;
}
var newDfd = test();
newDfd.done(function () {
    alert('成功');
}).fail(function () {
    alert('失败');
});
newDfd.reject();//alert的是失败和rejected,状态值被修改了

改为这样:

function test() {
    var dfd = $.Deferred();
    alert(dfd.state());
    setTimeout(function () {
        dfd.resolve();
        alert(dfd.state());
    }, 1000);
    return dfd.promise();//promise()转换成了promise
}
var newDfd = test();
newDfd.done(function () {
    alert('成功');
}).fail(function () {
    alert('失败');
});
newDfd.reject();//alert的是成功和resolved,状态值没被修改

 

promise的成员

1.state:返回Deferred的状态

state: function() {
    return state;
},

2.always:我的理解为老是执行的意思,调用了done和fail方法,无论调用的是 deferred.resolve() 仍是 deferred.reject(),都会调用想对应的方法

always: function() {
    deferred.done( arguments ).fail( arguments );
    return this;
},

3.then:传递3个参数,分别是done、fail和progress方法,分别调用执行封装一个快捷方式

then: function( /* fnDone, fnFail, fnProgress */ ) {
    var fns = arguments;// 参数为传入的 done 、 fail 、progress 函数

    //闭包
    //1。先建立一个新的Deferred,同时会执行func.call( deferred, deferred );这里newDefer = deferred
    return jQuery.Deferred(function( newDefer ) {

                //tuples遍历
                jQuery.each( tuples, function( i, tuple ) {

                    var action = tuple[ 0 ],//表示三种状态 resolve|reject|notify 其中之一

                        // 分别对应 fnDone, fnFail, fnProgress(首先用 isFunction 判断传入的参数是不是方法,注意 && 在这里的用法)
                        fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];//对应的回调函数

                    // deferred[ done | fail | progress ] for forwarding actions to newDefer
                    deferred[ tuple[1] ](function() {//done fail progress,本质是callbacks的add,添加一个回调函数

                        var returned = fn && fn.apply( this, arguments );//fn不为false,执行参数的函数

                        //这里是对pipe的函数的做用
                        // 若是回调返回的是一个 Deferred 实例
                        if ( returned && jQuery.isFunction( returned.promise ) ) {
                            // 则继续派发事件
                            returned.promise()
                                .done( newDefer.resolve )
                                .fail( newDefer.reject )
                                .progress( newDefer.notify );
                        } else {
                            // 若是回调返回的不是一个 Deferred 实例,则被当作 args 由 XXXWith 派发出去,本质是fire
                            newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );

                        }

                    });
                });

        fns = null;// 销毁变量,防止内存泄漏(退出前手工设置null避免闭包形成的内存占用)

    }).promise();//这边返回了一个新的Deferred的promise();

then这边比较复杂,分两种状况

1).Deferred直接使用then,如:

var dfd = $.Deferred();
setTimeout(function(){
    //dfd.resolve();
    dfd.reject('hello world');
},1000);

dfd.then(function () {
    alert(1);
}, function () {
    alert(arguments[0]);
}, function () {
    alert(3);
});

这种比较好处理,源码中间接对then的参数进行了遍历,分别进行了callbacks的add操做,回调函数中的var returned = fn && fn.apply( this, arguments );这里对函数进行了调用

2).promise.pipe = promise.then中使用then,这边比较绕

具体看例子:

var dfd = $.Deferred();
setTimeout(function(){
    dfd.resolve('hi');
},1000);
var newDfd = dfd.pipe(function(){
    return arguments[0] + ' word';
});
newDfd.done(function(){
    alert( arguments[0] );
});

结果将会是弹出hi word,这样能够实现相似aop的思想

dfd.pipe的调用其实是调用了then,fns中对应的是return arguments[0] + 'word'函数,进行tuples的遍历, deferred[ tuple[1] ](function() {}中构造了一个新的函数进行了add,因此本质上进行了3种状态的add,即resolve|reject|notify都会进行想对一个你的函数调用

4.promise:有参数时是进行合并,没参数直接返回promise

promise: function( obj ) {//jQuery.extend( obj, promise ) 对应deferred对象,比promise多出3个函数
    return obj != null ? jQuery.extend( obj, promise ) : promise;
}

 

deferred的成员

将promise的对象成员赋给deferred,调用extend执行

promise.promise( deferred ); // 将promise的对象成员赋给deferred,调用extend执行
promise: function( obj ) {//jQuery.extend( obj, promise ) 对应deferred对象,比promise多出3个函数
    return obj != null ? jQuery.extend( obj, promise ) : promise;
}

关于多出的3个函数:在建立deferred时同时遍历了tuples,并将resolve | reject | notify添加到deferred中,能够看到并无对promise进行相对应的添加

// deferred[ resolve | reject | notify ],本质是属于fireWith方法
// deferred[ resolve | reject | notify ]
// tuple[0] == resolve | reject | notify
// 能够看到 resolve | reject | notify 其实就是 Callbacks 里边的 fire 方法
deferred[ tuple[0] ] = function() {
    deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
    return this;
};

 

具体源码分析

var tuples = [//映射数组
        // action, add listener, listener list, final state
        [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
        [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
        [ "notify", "progress", jQuery.Callbacks("memory") ]
        //done fail  progress对应Callbacks的add方法 , resolve|reject|notify对应Callbacks的fire方法
        //状态:resolved 完成 rejected 未完成 notify进行中
        //resolve/reject只会触发一次 notify进行屡次触发
    ],
    state = "pending", //状态变量,初始状态pending 的意思为待定

    // 具备 state、always、then、primise 方法
    promise = {

        // 返回一个 Deferred 对象的当前状态
        state: function() {
            return state;
        },

        // 它的做用是,无论调用的是 deferred.resolve() 仍是 deferred.reject() ,最后老是执行
        always: function() {
            deferred.done( arguments ).fail( arguments );
            return this;
        },

        // 把 done()、fail() 和 progress() 合在一块儿写
        // deferred.done(fnDone), fail(fnFail) , progress(fnProgress) 的快捷方式
        then: function( /* fnDone, fnFail, fnProgress */ ) {
            var fns = arguments;// 参数为传入的 done 、 fail 、progress 函数

            //闭包
            //1。先建立一个新的Deferred,同时会执行func.call( deferred, deferred );这里newDefer = deferred
            return jQuery.Deferred(function( newDefer ) {

                        //tuples遍历
                        jQuery.each( tuples, function( i, tuple ) {

                            var action = tuple[ 0 ],//表示三种状态 resolve|reject|notify 其中之一

                                // 分别对应 fnDone, fnFail, fnProgress(首先用 isFunction 判断传入的参数是不是方法,注意 && 在这里的用法)
                                fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];//对应的回调函数

                            // deferred[ done | fail | progress ] for forwarding actions to newDefer
                            deferred[ tuple[1] ](function() {//done fail progress,本质是callbacks的add,添加一个回调函数

                                var returned = fn && fn.apply( this, arguments );//fn不为false,执行参数的函数

                                //这里是对pipe的函数的做用
                                // 若是回调返回的是一个 Deferred 实例
                                if ( returned && jQuery.isFunction( returned.promise ) ) {
                                    // 则继续派发事件
                                    returned.promise()
                                        .done( newDefer.resolve )
                                        .fail( newDefer.reject )
                                        .progress( newDefer.notify );
                                } else {
                                    // 若是回调返回的不是一个 Deferred 实例,则被当作 args 由 XXXWith 派发出去,本质是fire
                                    newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );

                                }

                            });
                        });

                fns = null;// 销毁变量,防止内存泄漏(退出前手工设置null避免闭包形成的内存占用)

            }).promise();//这边返回了一个新的Deferred的promise();
        },
        // Get a promise for this deferred
        // If obj is provided, the promise aspect is added to the object
        promise: function( obj ) {//jQuery.extend( obj, promise ) 对应deferred对象,比promise多出3个函数
            return obj != null ? jQuery.extend( obj, promise ) : promise;
        }
    },
    deferred = {};

// Keep pipe for back-compat
promise.pipe = promise.then;

// Add list-specific methods
//遍历映射数组
jQuery.each( tuples, function( i, tuple ) {

    var list = tuple[ 2 ], //jQuery.Callbacks("once memory")
        stateString = tuple[ 3 ];// stateString 为最后的状态s

    // promise[ done | fail | progress ] = list.add 本质是属于回调对象Callable的方法
    promise[ tuple[1] ] = list.add; //Callbacks的add方法

    // Handle state
    if ( stateString ) {

        //修改状态,并使其它状态禁止调用
        list.add(function() {
            // state = [ resolved | rejected ]
            state = stateString;

        },
            // [ reject_list | resolve_list ].disable; progress_list.lock
            // 这里用到了 disable ,便是禁用回调列表中的回调
            // 禁用对立的那条队列
            // 异或 0^1 = 1   1^1 = 0
            // 便是成功的时候,把失败那条队列禁用
            // 便是成功的时候,把成功那条队列禁用
            tuples[ i ^ 1 ][ 2 ].disable,
            // 锁住当前队列状态
            tuples[ 2 ][ 2 ].lock
        );
    }

    // deferred[ resolve | reject | notify ],本质是属于fireWith方法
    // deferred[ resolve | reject | notify ]
    // tuple[0] == resolve | reject | notify
    // 能够看到 resolve | reject | notify 其实就是 Callbacks 里边的 fire 方法
    deferred[ tuple[0] ] = function() {
        deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
        return this;
    };

    // deferred[resolveWith | rejectWith | notifyWith] 调用的是 Callbacks 里的 fireWith 方法
    deferred[ tuple[0] + "With" ] = list.fireWith;
});

// Make the deferred a promise
promise.promise( deferred ); // 将promise的对象成员赋给deferred,调用extend执行

// Call given func if any
if ( func ) {
    //把当前任务的上下文跟参数设置成当前生成的deferred实例
    func.call( deferred, deferred );
}

// All done!
// 返回实例,显而易见 Deferred 是个工厂类,返回的是内部构建的 deferred 对象
return deferred;
相关文章
相关标签/搜索