jquery 实现原理四:deferred对象

一,deferred的使用和基本原理

具体的用法可以参见阮一峰的一篇日志: http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
简单的说,deferred对象就是一个异步回调队列。
deferred对象最大的作用就是用在ajax中实现异步回调,
在没有deferred对象是,ajax必须这样写:
$.ajax({
     url: 'xxx',
     success: function(){}
     error: function() {}
})
这样的写法非常死板,即不方便定义多个回调,也不能写成链式操作。

在1.5版本引入deferred对象之后,ajax被用deferred改写,ajax方法返回的不再是ajax对象,而是deferred对象,所以可以实现这样的写法:
$.ajax('/xxx').success(function(){}).fail(function(){})

deferred的基本原理就是:

它定义了两种基本状态:resolved和rejected,然后定义了三个方法success,fail,always来定义当deferred对象从初始状态转换到两种基本状态时候应该调用哪些函数。最后提供了reject/rejectWith,resolve/resolveWith来改变deferred对象的状态,以便出发对应的回调函数


deferred对象的用途就是对那些非常费时的操作定义回调函数

二,deferred对象的实现

deferred对象的实现会依赖callback对象来管理回调函数队列。
先说下callback,他就是一个回调函数队列,提供add方法想队列里面添加内容,然后提供fire/fireWith对象来调用回调函数。

所以,deferred的实现比较简单
下面对源码逐段解析

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") ]
               ],
首先定义tuples数组,方便后面引用。

var promise={}
然后定义了一个promise对象
注意promise和deferred对象的区别:
promise方法已经被混入deferred对象了,但是deferred对象的一些方法没有在promise中,主要就是触发状态转换和函数回调的几个方法比如reject/rejectWith。
所以promise能做的 deferred都能做到,但是deferred能触发状态转换确实promise做不到的。所以使用promise方法返回promise对象可以防止被其他人改变自己的状态,他们只能通过promise来注册回调,但是不能通过promise来改变状态。
只是需要注意其中的两个方法:
then: 返回的是promise对象,然后默认把三个参数分别作为resolve, reject, notify状态的回调,所以这个方法就可以当做是需要连续定义三种回调的一个快捷方式
promise: 返回promise对象

deferred = {}; 
jQuery.each( tuples, function( i, tuple ) {
               var list = tuple[ 2 ],
                    stateString = tuple[ 3 ];

               // promise[ done | fail | progress ] = list.add
               promise[ tuple[1] ] = list.add;

               // Handle state
               if ( stateString ) {
                    list.add(function() {
                         // state = [ resolved | rejected ]
                         state = stateString;

                    // [ reject_list | resolve_list ].disable; progress_list.lock
                    }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
               }

               // deferred[ resolve | reject | notify ]
               deferred[ tuple[0] ] = function() {
                    deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
                    return this;
               };
               deferred[ tuple[0] + "With" ] = list.fireWith;
          });
然后就定义了一个deferred对象,并添加了很多方法,因为是通过遍历tuple来逐个添加的,可以以tuples[0]为例
tuples[0]=  [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ]
首先定义了 list =  jQuery.Callbacks("once memory")也就是一个回调队列
然后 promise['resolve'] = list.add,所以直接调用promise.resolve(fun)就是把这个函数添加到resolved队列中
下面是就是加锁操作
在下面,定义了 promise.resolveWith = list.fireWidth, 而 promise.resolve 就是 promise.resolveWidth 就是调用promise.resolve 但是this设了默认值。
整个deferred对象的构造是非常简单的,基本就是调用callback来实现存储和调用回调队列,然后引用下callback的部分函数

需要注意一点就是下面的代码
Deferred: function( func ) {
     ……
     if ( func ) {
               func.call( deferred, deferred );
          }

          // All done!
          return deferred;
}
所以说你如果这样调用 $.Deferred(fun),那么会调用fun并传入一个deferred对象,如果没有fun,则直接返回deferred对象。
 

你可能感兴趣的:(jquery,实现原理)