GAMELOFT9----讀萬卷書,行萬里路,知行合一
Deferred物件是由$.Deferred構造的,$.Deferred被實現為簡單工廠模式。
它用來解決JS中的非同步程式設計,它遵循 Common Promise/A 規範。實現此規範的還有 when.js 和 dojo。
$.Deferred作為新特性首次出現在版本1.5中,這個版本利用Deferred又完全重寫了Ajax模組。
$.Deferred在jQuery程式碼自身四處被使用,分別是promise方法、DOM ready、Ajax模組、動畫模組。
這裡以版本1.8.3分析,由於1.7後$.Callbacks從Deferred中抽離出去了,目前版本的deferred.js程式碼不過150行,而真正$.Deferred的實現只有100行左右。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
jQuery.extend({
Deferred: function (
func ) {
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" )
]
],
...
//
All done!
return deferred;
},
//
Deferred helper
when: function (
subordinate /*
, ..., subordinateN */ )
{
var i
= 0,
resolveValues
= core_slice.call( arguments ),
length
= resolveValues.length,
....
return deferred.promise();
}
});
|
$.Deferred的實現
- 建立三個$.Callbacks物件,分別表示成功,失敗,處理中三種狀態
- 建立了一個promise物件,具有state、always、then、primise方法
- 通過擴充套件primise物件生成最終的Deferred物件,返回該物件
$.when的實現
- 接受若干個物件,引數僅一個且非Deferred物件將立即執行回撥函式
- Deferred物件和非Deferred物件混雜時,對於非Deferred物件remaining減1
- Deferred物件總數 = 內部構建的Deferred物件 + 所傳引數中包含的Deferred物件
- 所傳引數中所有Deferred物件每當resolve時remaining減1,直到為0時(所有都resolve)執行回撥
這就是$.Deferred和$.when的全部了,各個方法及使用稍後介紹。
程式碼閱讀中會發現then和when方法的實現最難理解,看多次,後感回味無窮,非常巧妙。then內部會用到不同尋常的遞迴,when用到了計數,每次非同步成功後減一,直到為0後表示全部非同步操作成功,這時才可執行回撥。
上面提到Deferred裡有3個$.Callbacks的例項,Deferred自身則圍繞這三個物件進行更高層次的抽象。以下是Deferred物件的核心方法
- done/fail/progress 是 callbacks.add,將回調函式存入
- resolve/reject/notify 是 callbacks.fire,執行回撥函式(或佇列)
下面舉一些示例看看如何使用Deferred物件。
一、done/resolve