用下面的例子分析(見右側(cè)代碼編輯器):
var defer = $.Deferred(); defer.resolve(5); defer.done(function(value) {}) var filtered = defer.then(function(value) { return value * 2; }); filtered.done(function(value) {});
這里有幾個關(guān)鍵的問題:
1、defer延時對象通過resolved觸發(fā)done成功回調(diào),調(diào)用在添加done之前,那么靠什么延時處理?
2、為什么defer.then對象返回的給filtered.done的數(shù)據(jù)可以類似管道風(fēng)格的順序疊加給后面的done處理?
一般來說,javascript要實(shí)現(xiàn)異步的收集,就需要“等待”,比如defer.resolve(5)雖然觸發(fā)了,但是done的處理還沒添加,我們必須要等待done、then等方法先添加了后才能執(zhí)行了resolve,那么常規(guī)的的用法就是在resolve內(nèi)部用setTimeout 0,image.onerror行成一個異步的等待操作處理。
但是jQuery很巧妙的繞過了這個收集方式,
defer.resolve(5)方法實(shí)際就是觸發(fā)了callback回到函數(shù)的fireWith方法,這樣可以接受一個上下文deferred與參數(shù)5
deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments);
之前 done | fail | progress方法都是通過jQuery.Callbacks("once memory") 或 jQuery.Callbacks("memory")生成的。
實(shí)際上在Callback源碼fire方法有一句 memory = options.memory && data;這樣就很巧妙的緩存當(dāng)前參數(shù)5的值,提供給下一個使用,這個就是then,pipe鏈?zhǔn)綌?shù)據(jù)的一個基礎(chǔ)了,此刻的操作,我們把memory保存了這個數(shù)據(jù)的值。
重點(diǎn)來了,下一個defer.done的操作也是走的add的處理,把done的回調(diào)函數(shù)加入到list隊列中的之后,接著就會觸發(fā)。
// With memory, if we're not firing then // we should call right away } else if (memory) { firingStart = start; fire(memory); }
因?yàn)閙emory在上一個resolve操作的時候,緩存了5了,所以memory的判斷顯示是為真的,所以立刻就觸發(fā)了fire(memory)的代碼了,所以就算觸發(fā)的循序與添加的循序不一致,也不會導(dǎo)致錯誤。 而且jquery很巧妙的避免了異步收集的問題,這樣處理更可靠了??梢娀卣{(diào)函數(shù)模塊就是為Deferred模塊量身定做的了。
第二個問題,是關(guān)于then,pipe管道風(fēng)格的處理,這樣也是一個很復(fù)雜的設(shè)計,在后面一章就提到了。
請驗(yàn)證,完成請求
由于請求次數(shù)過多,請先驗(yàn)證,完成再次請求
打開微信掃碼自動綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報