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;