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"); });
参数说明:ide
1.func将做为异步函数传入Deferred对象,并立刻进行调用函数
var dfd = $.Deferred( function () { alert(111);//控制台弹出111 } );
参数处理:工具
if ( func ) { //Deferred中判断有参数传入后进行立刻调用,并将自身对象传入改函数 func.call( 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,状态值没被修改
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; }
将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;