在上一節(jié)中構(gòu)建了deferred對(duì)象,實(shí)現(xiàn)了done/fail/process和resolve/reject/notify等方法,但是最重要的then,pipe管道接口我們還沒(méi)有實(shí)現(xiàn),我們考慮下:
var dfd = $.Deferred() dfd.then(function(preVale) { return 2 * preVale //4 }).then(function(preVale) { return 3 * preVale //12 }) dfd.resolve(2)
then就是pipe,我們可以想象是一個(gè)管道,可以對(duì)回調(diào)模式使用瀑布模型。如案例所示,下一個(gè)回調(diào)都能取到上一個(gè)回調(diào)的值,這樣一直可以疊加往后傳遞。
不難看出管道的風(fēng)格就是鏈?zhǔn)降牟僮鳎恳粋€(gè)鏈上的結(jié)果都會(huì)反饋后下一個(gè)鏈,那么這個(gè)鏈?zhǔn)绞遣皇莻鹘y(tǒng)的返回自身這個(gè)對(duì)象this呢?
常規(guī)的辦法通過(guò)數(shù)組處理:右側(cè)代碼所示。
function aDeferred(){ //代碼右側(cè)代碼 }
這樣的結(jié)構(gòu)當(dāng)然是很簡(jiǎn)陋的,這里我們最終有一個(gè)本質(zhì)的問(wèn)題沒(méi)有解決,jQuery中的then的返回還有可能是另一個(gè)新的異步模型對(duì)象,如ajax,因此還能實(shí)現(xiàn)done,fail,always,then等方法。所以采用簡(jiǎn)陋的數(shù)組的方式保存狀態(tài)是很膚淺的了。
這時(shí)候jQuery采取了對(duì)象保存處理:
我們可以把每一次的then操作,當(dāng)做是創(chuàng)建一個(gè)新的deferred對(duì)象,那么每一個(gè)對(duì)象都?jí)虮4孀约旱臓顟B(tài)與各自的處理方法。通過(guò)一個(gè)辦法把所有的對(duì)象操作都串聯(lián)起來(lái),這就是then或者pipe管道設(shè)計(jì)的核心思路了。
看jQuery的then結(jié)構(gòu):
then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred(function(newDefer) { jQuery.each(tuples, function(i, tuple) { deferred[tuple[1]](function() { // deferred[ done | fail | progress ] }); }); }).promise()
其實(shí)在內(nèi)部創(chuàng)建了一個(gè)新的Deferred對(duì)象,不過(guò)這里的不同是通過(guò)傳遞一個(gè)回調(diào)函數(shù),參數(shù)是newDefer,其實(shí)Deferred內(nèi)部就是為了改變下上下文this為deferred,然后傳遞deferred給這個(gè)回調(diào)函數(shù)了,所以newDefer就指向內(nèi)部的deferred對(duì)象了。
那么對(duì)象之間如何關(guān)聯(lián)?
jQuery.each(tuples, function(i, tuple) { //取出參數(shù) var fn = jQuery.isFunction(fns[i]) && fns[i]; // deferred[ done | fail | progress ] for forwarding actions to newDefer // 添加done fail progress的處理方法 // 針對(duì)延時(shí)對(duì)象直接做了處理 deferred[tuple[1]](function() { var returned = fn && fn.apply(this, arguments); if (returned && jQuery.isFunction(returned.promise)) { returned.promise() .done(newDefer.resolve) .fail(newDefer.reject) .progress(newDefer.notify); } else { newDefer[tuple[0] + "With"](this === promise ? newDefer.promise() : this, fn ? [returned] : arguments); } });
把then的方法通過(guò):
deferred.done deferred.fail deferred.progress
加入到上一個(gè)對(duì)象的各自的執(zhí)行隊(duì)列中保存了。這樣就實(shí)現(xiàn)了不同對(duì)象之間的關(guān)聯(lián)調(diào)用。
同樣如果then返回的是一個(gè)promise對(duì)象(ajax)的時(shí)候:
if (returned && jQuery.isFunction(returned.promise)) { returned.promise() .done(newDefer.resolve) .fail(newDefer.reject) .progress(newDefer.notify);
也可以直接處理了。
請(qǐng)驗(yàn)證,完成請(qǐng)求
由于請(qǐng)求次數(shù)過(guò)多,請(qǐng)先驗(yàn)證,完成再次請(qǐng)求
打開(kāi)微信掃碼自動(dòng)綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報(bào)