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

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

基本使用

Deferred延迟对象是基于Callbacks对象的,所以要先熟悉Callbacks

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

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

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.未完成

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)参数

参数说明:

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;

 

转载于:https://my.oschina.net/u/2460728/blog/1524681

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值