自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

最細(xì)的實(shí)現(xiàn)剖析:jQuery 2.0.3源碼分析Deferred

開(kāi)發(fā) 前端
源碼還是要靠自己去折騰的,思想的提高比較難的,我們可以借鑒設(shè)計(jì)的思路,代碼書(shū)寫(xiě)方式都是有益無(wú)害的。流程的分析已經(jīng)比較透徹。

Deferred的概念請(qǐng)看第一篇

http://www.cnblogs.com/aaronjs/p/3348569.html

******************構(gòu)建Deferred對(duì)象時(shí)候的流程圖**************************

**********************源碼解析**********************

因?yàn)閏allback被剝離出去后,整個(gè)deferred就顯得非常的精簡(jiǎn)

  1. jQuery.extend({   
  2.  
  3.     Deferred : function(){}  
  4.       
  5.     when : function()  
  6.  
  7. )} 

對(duì)于extend的繼承這個(gè)東東,在之前就提及過(guò)jquery如何處理內(nèi)部jquery與init相互引用this的問(wèn)題

對(duì)于JQ的整體架構(gòu)一定要弄懂 http://www.cnblogs.com/aaronjs/p/3278578.html

所以當(dāng)jQuery.extend只有一個(gè)參數(shù)的時(shí)候,其實(shí)就是對(duì)jQuery靜態(tài)方法的一個(gè)擴(kuò)展

我們?cè)诰唧w看看2個(gè)靜態(tài)方法內(nèi)部都干了些什么

Deferred整體結(jié)構(gòu):

源碼精簡(jiǎn)了部分代碼

  1. Deferred: function( func ) {  
  2.         var tuples = [  
  3.                 // action, add listener, listener list, final state  
  4.                 [ "resolve""done", jQuery.Callbacks("once memory"), "resolved" ],  
  5.                 [ "reject""fail", jQuery.Callbacks("once memory"), "rejected" ],  
  6.                 [ "notify""progress", jQuery.Callbacks("memory") ]  
  7.             ],  
  8.             state = "pending",  
  9.             promise = {  
  10.                 state: function() {},  
  11.                 always: function() {},  
  12.                 then: function/* fnDone, fnFail, fnProgress */ ) { },  
  13.                 // Get a promise for this deferred  
  14.                 // If obj is provided, the promise aspect is added to the object  
  15.                 promise: function( obj ) {}  
  16.             },  
  17.             deferred = {};  
  18.         jQuery.each( tuples, function( i, tuple ) {  
  19.             deferred[ tuple[0] + "With" ] = list.fireWith;  
  20.         });  
  21.         promise.promise( deferred );  
  22.         // All done!  
  23.         return deferred;  
  24.     }, 
  1. 顯而易見(jiàn)Deferred是個(gè)工廠類,返回的是內(nèi)部構(gòu)建的deferred對(duì)象
  2. tuples 創(chuàng)建三個(gè)$.Callbacks對(duì)象,分別表示成功,失敗,處理中三種狀態(tài)
  3. 創(chuàng)建了一個(gè)promise對(duì)象,具有state、always、then、primise方法
  4. 擴(kuò)展primise對(duì)象生成最終的Deferred對(duì)象,返回該對(duì)象

這里其實(shí)就是3個(gè)處理,但是有個(gè)優(yōu)化代碼的地方,就是把共性的代碼給抽象出來(lái),通過(guò)動(dòng)態(tài)生成了

具體源碼分析:

Deferred自身則圍繞這三個(gè)對(duì)象進(jìn)行更高層次的抽象

  • 觸發(fā)回調(diào)函數(shù)列表執(zhí)行(函數(shù)名)
  • 添加回調(diào)函數(shù)(函數(shù)名)
  • 回調(diào)函數(shù)列表(jQuery.Callbacks對(duì)象)
  • deferred最終狀態(tài)(第三組數(shù)據(jù)除外)
  1. var tuples = [  
  2.         // action, add listener, listener list, final state  
  3.         [ "resolve""done", jQuery.Callbacks("once memory"), "resolved" ],  
  4.         [ "reject""fail", jQuery.Callbacks("once memory"), "rejected" ],  
  5.         [ "notify""progress", jQuery.Callbacks("memory") ]  
  6.     ], 

這里抽象出2組陣營(yíng):

1組:回調(diào)方法/事件訂閱  

  1. done,fail,progress 

2組:通知方法/事件發(fā)布    

  1. resolve,reject,notify,resolveWith,rejectWith,notifyWith 

tuples 元素集 其實(shí)是把相同有共同特性的代碼的給合并成一種結(jié)構(gòu),然后通過(guò)一次處理

  1. jQuery.each( tuples, function( i, tuple ) {  
  2.             var list = tuple[ 2 ],  
  3.                 stateString = tuple[ 3 ];  
  4.             promise[ tuple[1] ] = list.add;  
  5.             if ( stateString ) {  
  6.                 list.add(function() {  
  7.                     state = stateString;  
  8.  
  9.                 // [ reject_list | resolve_list ].disable; progress_list.lock  
  10.                 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );  
  11.             }  
  12.             deferred[ tuple[0] ] = function() {  
  13.                 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );  
  14.                 return this;  
  15.             };  
  16.             deferred[ tuple[0] + "With" ] = list.fireWith;  
  17.         }); 

對(duì)于tuples的3條數(shù)據(jù)集是分2部分處理的

第一部分將回調(diào)函數(shù)存入

  1. promise[ tuple[1] ] = list.add; 

其實(shí)就是給promise賦予3個(gè)回調(diào)函數(shù)

  1. promise.done = $.Callbacks("once memory").add 
  1. promise.fail = $.Callbacks("once memory").add 
  1. promise.progressl = $.Callbacks("memory").add 

如果存在deferred最終狀態(tài)

默認(rèn)會(huì)預(yù)先向doneList,failList中的list添加三個(gè)回調(diào)函數(shù)

  1. if ( stateString ) {  
  2.     list.add(function() {  
  3.         // state = [ resolved | rejected ]  
  4.         state = stateString;  
  5.  
  6.     // [ reject_list | resolve_list ].disable; progress_list.lock  
  7.     }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );  

*************************************************************
這里有個(gè)小技巧

i ^ 1 按位異或運(yùn)算符

所以實(shí)際上第二個(gè)傳參數(shù)是1、0索引對(duì)調(diào)了,所以取值是failList.disable與doneList.disable

************************************************************* 

通過(guò)stateString有值這個(gè)條件,預(yù)先向doneList,failList中的list添加三個(gè)回調(diào)函數(shù)

分別是:

  1. doneList : [changeState, failList.disable, processList.lock]  
  2. failList : [changeState, doneList.disable, processList.lock] 
  • changeState 改變狀態(tài)的匿名函數(shù),deferred的狀態(tài),分為三種:pending(初始狀態(tài)), resolved(解決狀態(tài)), rejected(拒絕狀態(tài))
  • 不論deferred對(duì)象最終是resolve(還是reject),在首先改變對(duì)象狀態(tài)之后,都會(huì)disable另一個(gè)函數(shù)列表failList(或者doneList)
  • 然后lock processList保持其狀態(tài),最后執(zhí)行剩下的之前done(或者fail)進(jìn)來(lái)的回調(diào)函數(shù)

所以第一步最終都是圍繞這add方法

  • done/fail/是list.add也就是callbacks.add,將回調(diào)函數(shù)存入回調(diào)對(duì)象中

第二部分很簡(jiǎn)單,給deferred對(duì)象擴(kuò)充6個(gè)方法

最后合并promise到deferred

  1. promise.promise( deferred );  
  2. jQuery.extend( obj, promise ) 

所以最終通過(guò)工廠方法Deferred構(gòu)建的異步對(duì)象帶的所有的方法了

return 內(nèi)部的deferred對(duì)象了

由此可見(jiàn)我們?cè)?/p>

  1. var defer = $.Deferred(); //構(gòu)建異步對(duì)象 

的時(shí)候,內(nèi)部的對(duì)象就有了4個(gè)屬性方法了

  1. deferred: Object
    1. always: function () {
    2. done: function () {
    3. fail: function () {
    4. notify: function () {
    5. notifyWith: function ( context, args ) {
    6. pipe: function ( /* fnDone, fnFail, fnProgress */ ) {
    7. progress: function () {
    8. promise: function ( obj ) {
    9. reject: function () {
    10. rejectWith: function ( context, args ) {
    11. resolve: function () {
    12. resolveWith: function ( context, args ) {
    13. state: function () {
    14. then: function ( /* fnDone, fnFail, fnProgress */ ) {
  2. promise: Object
    1. always: function () {
    2. done: function () {
    3. fail: function () {
    4. pipe: function ( /* fnDone, fnFail, fnProgress */ ) {
    5. progress: function () {
    6. promise: function ( obj ) {
    7. state: function () {
    8. then: function ( /* fnDone, fnFail, fnProgress */ ) {
  3. state: "pending"
  4. tuples: Array[3]

構(gòu)造圖

以上只是在初始化構(gòu)建的時(shí)候,我們往下看看動(dòng)態(tài)執(zhí)行時(shí)候的處理

#p#

*****************執(zhí)行期***********************

一個(gè)最簡(jiǎn)單的demo為例子

  1. var d = $.Deferred();  
  2.  
  3.  setTimeout(function(){  
  4.         d.resolve(22)  
  5.   },0);  
  6.  
  7.  d.then(function(val){  
  8.       console.log(val);  
  9.  }) 

當(dāng)延遲對(duì)象被 resolved 時(shí),任何通過(guò) deferred.then或deferred.done 添加的 doneCallbacks,都會(huì)被調(diào)用?;卣{(diào)函數(shù)的執(zhí)行順序和它們被添加的順序是一樣的。傳遞給 deferred.resolve() 的 args 參數(shù),會(huì)傳給每個(gè)回調(diào)函數(shù)。當(dāng)延遲對(duì)象進(jìn)入 resolved 狀態(tài)后,再添加的任何 doneCallbacks,當(dāng)它們被添加時(shí),就會(huì)被立刻執(zhí)行,并帶上傳入給 .resolve()的參數(shù)

換句話說(shuō),我們調(diào)用d.resolve(22) 就等于是調(diào)用。

匿名函數(shù)并傳入?yún)?shù)值 22

  1. function(val){  
  2.       console.log(val); //22  
  3.  } 

當(dāng)前實(shí)際的使用中會(huì)有各種復(fù)雜的組合情況,但是整的外部調(diào)用流程就是這樣的

***************** resolve的實(shí)現(xiàn) *******************

我們回顧下,其實(shí)Deferred對(duì)象,內(nèi)部的實(shí)現(xiàn)還是Callbacks對(duì)象,只是在外面再封裝了一層API,供接口調(diào)用

  1. d.resolve(22) 

實(shí)際上調(diào)用的就是通過(guò)這個(gè)代碼生成的

  1. deferred[ tuple[0] ] = function() {  
  2.     deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );  
  3.     return this;  
  4. };  
  5.  
  6. deferred[ tuple[0] + "With" ] = list.fireWith; 
  1. deferred.resolveWith() 

最終執(zhí)行的就是 list.fireWith

  1. callbacks.fireWith() 

所以最終又回到回調(diào)對(duì)象callbacks中的私有方法fire()了

 

Callbacks會(huì)通過(guò)

callbacks.add()

把回調(diào)函數(shù)給注冊(cè)到內(nèi)部的list = []上,我們回來(lái)過(guò)看看

deferred.then()

  1. d.then(function(val){  
  2.       console.log(val);  
  3.  }) 

***************** then的實(shí)現(xiàn) *******************

  1. then: function/* fnDone, fnFail, fnProgress */ ) {  
  2.     var fns = arguments;  
  3.     return jQuery.Deferred(function( newDefer ) {  
  4.         jQuery.each( tuples, function( i, tuple ) {  
  5.             var action = tuple[ 0 ],  
  6.                 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];  
  7.             // deferred[ done | fail | progress ] for forwarding actions to newDefer  
  8.             deferred[ tuple[1] ](function() {  
  9.                    //省略............  
  10.             });  
  11.         });  
  12.         fns = null;  
  13.     }).promise();  
  14. }, 
  • 遞歸jQuery.Deferred
  • 傳遞了func
  • 鏈?zhǔn)秸{(diào)用了promise()

因?yàn)樵诋惒綄?duì)象的方法都是嵌套找作用域?qū)傩苑椒ǖ?/strong>

這里我額外的提及一下作用域

  1. var d = $.Deferred(); 

這個(gè)異步對(duì)象d是作用域是如何呢?

第一層:無(wú)可爭(zhēng)議,瀏覽器環(huán)境下最外層是 window

第二層:jquery本身是一個(gè)閉包

第三層: Deferred工廠方法產(chǎn)生的作用域

如果用d.then()方法呢?

很明顯then方法又是嵌套在內(nèi)部的函數(shù),所以執(zhí)行的時(shí)候都默認(rèn)會(huì)包含以上三層作用域+自己本身函數(shù)產(chǎn)生的作用域了

我們用個(gè)簡(jiǎn)單圖描繪下

演示文稿1

根據(jù)規(guī)則,在最內(nèi)部的函數(shù)能夠訪問(wèn)上層作用域的所有的變量

我們先從使用的層面去考慮下結(jié)構(gòu)設(shè)計(jì):

demo 1

  1. var defer = $.Deferred();  
  2.  
  3.   var filtered = defer.then(function( value ) {  
  4.         return value * 2;  
  5.       });  
  6.  
  7.   defer.resolve( 5 );  
  8.  
  9.   filtered.done(function( value ) {  
  10.       console.log(value) //10  
  11.   }); 

demo 2

  1. var defer = $.Deferred();  
  2.  
  3.   defer.then(function(value) {  
  4.     return value * 2;  
  5.   }).then(function(value) {  
  6.     return value * 2;  
  7.   }).done(function(value) {  
  8.       alert(value)  //20  
  9.   });  
  10.  
  11.   defer.resolve( 5 ); 

其實(shí)這里就是涉及到defer.then().then().done()  鏈?zhǔn)秸{(diào)用了

API是這么定義的:

  1. deferred.then( doneFilter [, failFilter ] [, progressFilter ] ) 

從jQuery 1.8開(kāi)始, 方法返回一個(gè)新的promise(承諾),通過(guò)一個(gè)函數(shù),可以過(guò)濾deferred(延遲)的狀態(tài)和值。替換現(xiàn)在過(guò)時(shí)的deferred.pipe()方法。 doneFilter 和 failFilter函數(shù)過(guò)濾原deferred(延遲)的解決/拒絕的狀態(tài)和值。 progressFilter 函數(shù)過(guò)濾器的任何調(diào)用到原有的deferred(延遲)的notify 和 notifyWith的方法。 這些過(guò)濾器函數(shù)可以返回一個(gè)新的值傳遞給的 promise(承諾)的.done() 或 .fail() 回調(diào),或他們可以返回另一個(gè)觀察的對(duì)象(遞延,承諾等)傳遞給它的解決/拒絕的狀態(tài)和值promise(承諾)的回調(diào)。 如果過(guò)濾函數(shù)是空,或沒(méi)有指定,promise(承諾)將得到與原來(lái)值相同解決(resolved)或拒絕(rejected)。

我們抓住幾點(diǎn):

  • 返回的是新的promise對(duì)象
  • 內(nèi)部有一個(gè)濾器函數(shù)

從demo 1中我們就能看到

經(jīng)過(guò)x.then()方法處理的代碼中返回的this(filtered ),不是原來(lái)的$.Deferred()所有產(chǎn)生的那個(gè)異步對(duì)象(defer )了

#p#

所以,每經(jīng)過(guò)一個(gè)then那么內(nèi)部處理的this都要被重新設(shè)置,那么為什么要這樣處理呢?

源碼

  1. then: function/* fnDone, fnFail, fnProgress */ ) {  
  2.                     var fns = arguments;  
  3.                     //分別為deferred的三個(gè)callbacklist添加回調(diào)函數(shù),根據(jù)fn的是否是函數(shù),分為兩種情況  
  4.                     return jQuery.Deferred(function( newDefer ) {  
  5.                         jQuery.each( tuples, function( i, tuple ) {  
  6.                             var action = tuple[ 0 ],  
  7.                                 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];  
  8.                             // deferred[ done | fail | progress ] for forwarding actions to newDefer  
  9.                             deferred[ tuple[1] ](function() {  
  10.                                 var returned = fn && fn.apply( this, arguments );  
  11.                                 if ( returned && jQuery.isFunction( returned.promise ) ) {  
  12.                                     returned.promise()  
  13.                                         .done( newDefer.resolve )  
  14.                                         .fail( newDefer.reject )  
  15.                                         .progress( newDefer.notify );  
  16.                                 } else {  
  17.                                     newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );  
  18.                                 }  
  19.                             });  
  20.                         });  
  21.                         fns = null;  
  22.                     }).promise();  
  23.                 }, 

在Deferred傳遞實(shí)參的時(shí)候,支持一個(gè)flag,jQuery.Deferred(func)

傳遞一個(gè)回調(diào)函數(shù)

  1. // Call given func if any  
  2. if ( func ) {  
  3.     func.call( deferred, deferred );  

所以newDefer可以看作是

  1. newDefer = $.Deferred(); 

那么func回調(diào)的處理的就是過(guò)濾函數(shù)了

  1. deferred[ tuple[1] ](function() {  
  2.     var returned = fn && fn.apply( this, arguments );  
  3.     if ( returned && jQuery.isFunction( returned.promise ) ) {  
  4.         returned.promise()  
  5.             .done( newDefer.resolve )  
  6.             .fail( newDefer.reject )  
  7.             .progress( newDefer.notify );  
  8.     } else {  
  9.         newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );  
  10.     }  
  11. }); 

這里其實(shí)也有編譯函數(shù)的概念,講未來(lái)要執(zhí)行的代碼,預(yù)先通過(guò)閉包函數(shù)也保存起來(lái),使其訪問(wèn)各自的作用域

第一步

分解tuples元素集

  1. jQuery.each( tuples, function( i, tuple ) {  
  2.    //過(guò)濾函數(shù)第一步處理  
  3. }) 

第二步

分別為deferred[ done | fail | progress ]執(zhí)行對(duì)應(yīng)的add方法,增加過(guò)濾函數(shù)給done | fail | progress 方法

  1. deferred[ tuple[1] ](  
  2. 傳入過(guò)濾函數(shù)  
  3. //過(guò)濾函數(shù) 執(zhí)行的時(shí)候在分解 

代碼即

  1. deferred[done] = list.add = callback.add 

第三步

返回return jQuery.Deferred().promise()

此時(shí)構(gòu)建了一個(gè)新的Deferred對(duì)象,但是返回的的是經(jīng)過(guò)promise()方法處理后的,返回的是一個(gè)受限的promise對(duì)象

所以整個(gè)then方法就處理了2個(gè)事情

  • 構(gòu)建一個(gè)新的deferred對(duì)象,返回受限的promise對(duì)象
  • 給父deferred對(duì)象的[ done | fail | progress ]方法都增加一個(gè)過(guò)濾函數(shù)的方法

我們知道defer.then方法返回的是一個(gè)新的jQuery.Deferred().promise()對(duì)象

那么我們把defer.then返回的稱之為子對(duì)象,那么如何與父對(duì)象var defer = $.Deferred() 關(guān)聯(lián)的起來(lái)的

我看看源碼

  1. deferred[ tuple[1] ](//過(guò)濾函數(shù)//) 

deferred其實(shí)就是根級(jí)父對(duì)象的引用,所以就嵌套再深,其實(shí)都是調(diào)用了父對(duì)象deferred[ done | fail | progress 執(zhí)行add罷了

 

從圖中就能很明顯的看到 2個(gè)不同的deferred對(duì)象中 done fail progress分別都保存了不同的處理回調(diào)了

deferred.resolve( args )

  • 當(dāng)延遲對(duì)象被 resolved 時(shí),任何通過(guò) deferred.thendeferred.done 添加的 doneCallbacks,都會(huì)被調(diào)用
  • 回調(diào)函數(shù)的執(zhí)行順序和它們被添加的順序是一樣的
  • 傳遞給 deferred.resolve() 的 args 參數(shù),會(huì)傳給每個(gè)回調(diào)函數(shù)
  • 當(dāng)延遲對(duì)象進(jìn)入 resolved 狀態(tài)后,再添加的任何 doneCallbacks,當(dāng)它們被添加時(shí),就會(huì)被立刻執(zhí)行,并帶上傳入給.resolve()的參數(shù)

流程如圖

 

流程解析:

1 執(zhí)行fire()方法,遞歸執(zhí)行l(wèi)ist所有包含的處理方法

2 執(zhí)行了默認(rèn)的 changeState, disable, lock 方法、

3 執(zhí)行過(guò)濾函數(shù)

      根據(jù) var returned = fn.apply( this, arguments )的返回值(稱作returnReferred)是否是deferred對(duì)象

  • 返回值是deferred對(duì)象,那么在returnReferred對(duì)象的三個(gè)回調(diào)函數(shù)列表中添加newDeferred的resolve(reject,notify)方法,也就是說(shuō)newDeferrred的執(zhí)行依賴returnDeferred的狀態(tài)

  • 不是函數(shù)的情況(如值為undefined或者null等),直接鏈接到newDeferred的resolve(reject,notify) 方法,也就是說(shuō)  newDeferrred的執(zhí)行依賴外層的調(diào)用者deferred的狀態(tài)或者說(shuō)是執(zhí)行動(dòng)作(resolve還是reject或者是notify)  此時(shí)deferred.then()相當(dāng)于將自己的callbacklist和newDeferred的callbacklist連接起來(lái)

下面就是嵌套deferred對(duì)象的劃分了

image

源碼還是要靠自己去折騰的,思想的提高比較難的,我們可以借鑒設(shè)計(jì)的思路,代碼書(shū)寫(xiě)方式都是有益無(wú)害的。

流程的分析已經(jīng)比較透徹了,下一章在講解when的實(shí)現(xiàn)。 

原文鏈接:http://www.cnblogs.com/aaronjs/p/3356505.html

責(zé)任編輯:林師授 來(lái)源: 博客園
相關(guān)推薦

2013-09-16 10:40:44

Sizzle

2011-08-22 16:19:58

jQuery

2015-07-16 14:24:44

jQueryAlpha

2011-03-11 09:20:35

jQueryjavascript

2024-01-19 12:48:00

Redis存儲(chǔ)數(shù)據(jù)庫(kù)

2021-04-15 09:07:52

hotspotJavaC++

2012-09-06 10:07:26

jQuery

2020-08-26 14:00:37

C++string語(yǔ)言

2022-09-27 18:56:28

ArrayList數(shù)組源代碼

2021-10-26 18:22:25

原理注冊(cè)表信息

2024-05-09 16:21:46

Deepseek技術(shù)算法

2021-02-26 13:59:41

RocketMQProducer底層

2025-03-31 00:00:00

MCPAPI服務(wù)器通信

2024-01-29 15:54:41

Java線程池公平鎖

2021-01-28 07:21:13

算法虛擬DOM前端

2020-10-09 14:13:04

Zookeeper Z

2022-04-29 14:56:40

通話應(yīng)用源碼剖析

2018-10-31 15:54:47

Java線程池源碼

2021-04-28 06:26:11

Spring Secu功能實(shí)現(xiàn)源碼分析

2011-04-21 10:45:34

ATLWTLCString
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)