Deferred 對(duì)象是在 jQuery1.5 中引入的回調(diào)管理對(duì)象。其作用,大概就是把一堆函數(shù)按順序放入一個(gè)調(diào)用鏈,然后根據(jù)狀態(tài),來(lái)依次調(diào)用這些函數(shù)。 AJAX 的所有操作都是使用它來(lái)進(jìn)行封裝的。比如我們定義的,當(dāng)請(qǐng)求正常返回時(shí),會(huì)調(diào)用 success 定義的函數(shù),失敗時(shí),會(huì)調(diào)用 error定義的函數(shù)。這里的“失敗”,“正?!本褪菭顟B(tài),而對(duì)應(yīng)的函數(shù),只是調(diào)用鏈中的一個(gè)而且。
先來(lái)看一個(gè)直觀(guān)的例子:
var obj = $.Deferred(function(a){}); obj.done(function(){console.log('1')}); obj.done(function(){console.log('2')}); obj.resolve();
這樣,我們就可以按順序看到 1 , 2 這兩個(gè)輸出了。
總的來(lái)說(shuō), jQuery 的 Deferred 對(duì)象有三個(gè)狀態(tài): done , fail , process 。
然后, jQuery 提供了一些函數(shù)用于添加回調(diào),激發(fā)狀態(tài)等:
如果一個(gè) Deferred 已經(jīng)被激發(fā),則新添加的對(duì)應(yīng)的函數(shù)會(huì)被立即執(zhí)行。
除了上面的這些操作函數(shù)之外, jQuery 還提供了一個(gè) jQuery.when() 的回調(diào)管理函數(shù),可以用于方便地管理多個(gè)事件并發(fā)的情況,先看一個(gè) AJAX 的“原始狀態(tài)”例子:
var defer = $.ajax({ url: '/json.html', dataType: 'json' }); defer.done(function(data){console.log(data)});
.done() 做的事和使用 success 定義是一樣的。
當(dāng)我們需要完成,像“請(qǐng)求A和請(qǐng)求B都完成時(shí),執(zhí)行函數(shù)”之類(lèi)的需求時(shí),使用 $.when() 就可以了:
var defer_1 = $.ajax({ url: '/json.html', dataType: 'json' }); var defer_2 = $.ajax({ url: '/jsonp.html', dataType: 'jsonp' }); var new_defer = $.when(defer_1, defer_2); new_defer.done(function(){console.log('haha')});
在 $.when() 中的 Deferred ,只要有一個(gè)是 fail ,則整體結(jié)果為 fail 。
Deferred 的回調(diào)函數(shù)的執(zhí)行順序與它們的添加順序一致。
這里特別注意一點(diǎn),就是 done / fail / always 與 then 的返回值的區(qū)別。從功能上看,它們都可以添加回調(diào)函數(shù),但是,方法的返回值是不同的。 前組的返回值是原來(lái)的那個(gè) defer 對(duì)象,而 then 返回的是一個(gè)新的 defer 對(duì)象。
then 返回新的 defer 這種形式,可以用于方便地實(shí)現(xiàn)異步函數(shù)的鏈?zhǔn)秸{(diào)用。
比如對(duì)于:
var defer = $.ajax({ url: '/json', dataType: 'json' });
如果使用 done 方法:
defer.done(function(){ return $.ajax({ url: '/json', dataType: 'json', success: function(){ console.log('inner') } }); }).done(function(){ console.log('here'); });
等同于是調(diào)用了兩次 defer.done
, defer.done
,注冊(cè)的兩次回調(diào)函數(shù)依次被執(zhí)行后,我們看到的輸出是:
here inner
這是兩次 defer.done
的結(jié)果,第一個(gè)回調(diào)函數(shù)返回了一個(gè)新的 defer 沒(méi)任何作用。
如果換成 then 方法的話(huà):
defer.then(function(){ return $.ajax({ url: '/json', dataType: 'json', success: function(){ console.log('inner') } }); }).done(function(){ console.log('here'); });
上面的代碼相當(dāng)于:
var new_defer = defer.then(...); new_defer.done(...);
它跟兩次 defer.done
是不同的。 new_defer
會(huì)在 inner
那里的 defer 被觸發(fā)時(shí)再被觸發(fā),所以輸出結(jié)果是:
inner here
更一般地來(lái)說(shuō) then 的行為,就是前面的注冊(cè)函數(shù)的返回值,會(huì)作為后面注冊(cè)函數(shù)的參數(shù)值:
var defer = $.ajax({ url: '/json', dataType: 'json' }); defer.then(function(res){ console.log(res); return 1; }).then(function(res){ console.log(res); return 2; }).then(function(res){ console.log(res); });
上面代碼的輸入結(jié)果是:
ajax response 1 2
更多建議: