deferred對象簡介
原文鏈接
http://www.jb51.net/article/28054.htm
開發(fā)網(wǎng)站的過程中蚂四,我們經(jīng)常遇到某些耗時(shí)很長的javascript操作逻恐。其中态辛,既有異步的操作(比如ajax讀取服務(wù)器數(shù)據(jù)),也有同步的操作(比如遍歷一個(gè)大型數(shù)組)瓦哎,它們都不是立即能得到結(jié)果的奇昙。
通常的解決方法是欢瞪,為它們指定回調(diào)函數(shù)(callback)。即事先規(guī)定碉纺,一旦它們運(yùn)行結(jié)束船万,應(yīng)該調(diào)用哪些函數(shù)细层。
但是,在回調(diào)函數(shù)方面唬涧,jQuery的功能非常弱疫赎。為了改變這一點(diǎn),jQuery開發(fā)團(tuán)隊(duì)就設(shè)計(jì)了deferred對象碎节。
簡單說捧搞,deferred對象就是jQuery的回調(diào)函數(shù)解決方案。在英語中狮荔,defer的意思是"延遲"胎撇,所以deferred對象的含義就是"延遲"到未來某個(gè)點(diǎn)再執(zhí)行。
ajax操作的鏈?zhǔn)綄懛?/p>
jQuery的ajax操作殖氏,傳統(tǒng)寫法是這樣的:
$.ajax({
url: "test.html",
success: function({
alert("哈哈晚树,成功了!");
},
error:function(){
alert("出錯(cuò)啦雅采!");
}
});
在上面的代碼中爵憎,$.ajax()接受一個(gè)對象參數(shù),這個(gè)對象包含兩個(gè)方法:success方法指定操作成功后的回調(diào)函數(shù)婚瓜,error方法指定操作失敗后的回調(diào)函數(shù)宝鼓。
$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery巴刻,返回的是XHR對象愚铡,你沒法進(jìn)行鏈?zhǔn)讲僮鳎蝗绻哂?.5.0版本胡陪,返回的是deferred對象沥寥,可以進(jìn)行鏈?zhǔn)讲僮鳌?/p>
鏈?zhǔn)叫聦懛ǎ?/p>
$.ajax("test.html").done(function(){alert('success');}).fail(function(){alert('failed')});
回調(diào)函數(shù)可以添加任意多個(gè),它們按照添加順序執(zhí)行柠座。
普通操作的回調(diào)函數(shù)接口
deferred對象的最大優(yōu)點(diǎn)邑雅,就是它把這一套回調(diào)函數(shù)接口,從ajax操作擴(kuò)展到了所有操作愚隧。也就是說蒂阱,任何一個(gè)操作----不管是ajax操作還是本地操作,也不管是異步操作還是同步操作----都可以使用deferred對象的各種方法狂塘,指定回調(diào)函數(shù)录煤。
我們來看一個(gè)具體的例子。假定有一個(gè)很耗時(shí)的操作wait:
var wait = function(){
var tasks = function(){
alert('done');
};
setTimeout(tasks, 5000);
};
**使用$.when:**
$.when(wait()).done(function{}).fail(function(){});
但是荞胡,有一個(gè)問題妈踊。$.when()的參數(shù)只能是deferred對象,所以必須對wait進(jìn)行改寫:
var dtd = $.Deferred();
var wait = function(dtd) {
var tasks = function(){
dtd.resolve();
};
setTimeout(tasks, 5000);
return dtd.promise();
}
***注意***
首先泪漂,最后一行不能直接返回dtd廊营,必須返回[dtd.promise()](http://api.jquery.com/deferred.promise/)歪泳。原因是jQuery規(guī)定,任意一個(gè)deferred對象有三種執(zhí)行狀態(tài)----未完成露筒,已完成和已失敗呐伞。如果直接返回dtd,$.when()的默認(rèn)執(zhí)行狀態(tài)為"已完成"慎式,立即觸發(fā)后面的done()方法伶氢,這就失去回調(diào)函數(shù)的作用了。dtd.promise()的目的瘪吏,就是保證目前的執(zhí)行狀態(tài)----也就是"未完成"----不變癣防,從而確保只有操作完成后,才會(huì)觸發(fā)回調(diào)函數(shù)掌眠。
其次蕾盯,當(dāng)操作完成后,必須手動(dòng)改變Deferred對象的執(zhí)行狀態(tài)蓝丙,否則回調(diào)函數(shù)無法觸發(fā)级遭。[dtd.resolve()](http://api.jquery.com/deferred.resolve/)的作用,就是將dtd的執(zhí)行狀態(tài)從"未完成"變成"已完成"迅腔,從而觸發(fā)done()方法装畅。
最后別忘了靠娱,修改完wait之后沧烈,調(diào)用的時(shí)候就必須直接傳入dtd參數(shù)。
$.when(wait(dtd)).don(function(){}).fail(function(){});
**使用$.Deferred()**
$.Deferred(wait).done(function(){}).fail(function(){});
jQuery規(guī)定像云,$.Deferred()可以接受一個(gè)函數(shù)作為參數(shù)锌雀,該函數(shù)將在$.Deferred()返回結(jié)果之前執(zhí)行。并且迅诬,$.Deferred()所生成的Deferred對象將作為這個(gè)函數(shù)的默認(rèn)參數(shù)腋逆。
**在wait對象上部署deferred接口**
var dtd = $.Derferred();
var wait = function(dtd){
var tasks = function(){
dtd.resolve();
};
setTimeout(tasks, 5000);
};
dtd.promise(wait);
wait.done(function(){}).fail(function(){});
wait(dtd);
>Deferred對象方法總結(jié)
(1)[$.Deferred()](http://api.jquery.com/category/deferred-object/)生成一個(gè)deferred對象。
〕薮(2)[deferred.done()](http://api.jquery.com/deferred.done/)指定操作成功時(shí)的回調(diào)函數(shù)
〕颓浮(3)[deferred.fail()](http://api.jquery.com/deferred.fail/)指定操作失敗時(shí)的回調(diào)函數(shù)
(4)[deferred.promise()](http://api.jquery.com/deferred.promise/)沒有參數(shù)時(shí)俏蛮,作用為保持deferred對象的運(yùn)行狀態(tài)不變撑蚌;接受參數(shù)時(shí),作用為在參數(shù)對象上部署deferred接口搏屑。
≌俊(5)[deferred.resolve()](http://api.jquery.com/deferred.resolve/)手動(dòng)改變deferred對象的運(yùn)行狀態(tài)為"已完成",從而立即觸發(fā)done()方法辣恋。
×恋妗(6)[$.when()](http://api.jquery.com/jQuery.when/)為多個(gè)操作指定回調(diào)函數(shù)模软。
除了這些方法以外,deferred對象還有三個(gè)重要方法饮潦,上面的教程中沒有涉及到燃异。
(7)[deferred.then()](http://api.jquery.com/deferred.then/)
有時(shí)為了省事继蜡,可以把done()和fail()合在一起寫特铝,這就是then()方法。
$.when($.ajax( "/main.php" ))
**.then(successFunc, failureFunc );**
如果then()有兩個(gè)參數(shù)壹瘟,那么第一個(gè)參數(shù)是done()方法的回調(diào)函數(shù)鲫剿,第二個(gè)參數(shù)是fail()方法的回調(diào)方法。如果then()只有一個(gè)參數(shù)稻轨,那么等同于done()灵莲。
(8)[deferred.reject()](http://api.jquery.com/deferred.reject/)
這個(gè)方法與deferred.resolve()正好相反殴俱,調(diào)用后將deferred對象的運(yùn)行狀態(tài)變?yōu)?已失敗"政冻,從而立即觸發(fā)fail()方法。
∠哂(9)[deferred.always()](http://api.jquery.com/deferred.always/)
這個(gè)方法也是用來指定回調(diào)函數(shù)的明场,它的作用是,不管調(diào)用的是deferred.resolve()還是deferred.reject()李丰,最后總是執(zhí)行苦锨。
$.ajax( "test.html" )
.always( function() { alert("已執(zhí)行!");} );