$.when()和deferred對象

一、什么是deferred對象又碌?

開發(fā)網(wǎng)站的過程中,我們經(jīng)常遇到某些耗時很長的javascript操作。其中银还,既有異步的操作(比如ajax讀取服務(wù)器數(shù)據(jù)),也有同步的操作(比如遍歷一個大型數(shù)組)洁墙,它們都不是立即能得到結(jié)果的见剩。

通常的解決方法是,為它們指定回調(diào)函數(shù)(callback)扫俺。即事先規(guī)定苍苞,一旦它們運行結(jié)束,應(yīng)該調(diào)用哪些函數(shù)狼纬。

但是羹呵,在回調(diào)函數(shù)方面,jQuery的功能非常弱疗琉。為了改變這一點冈欢,jQuery開發(fā)團隊就設(shè)計了deferred對象。

簡單說盈简,deferred對象就是jQuery的回調(diào)函數(shù)解決方案凑耻。 在英語中太示,defer的意思是"延遲",所以deferred對象的含義就是"延遲"到未來某個點再執(zhí)行香浩。

它解決了如何處理耗時操作的問題类缤,對那些操作提供了更好的控制,以及統(tǒng)一的編程接口邻吭。它的主要功能餐弱,可以歸結(jié)為四點。下面我們通過示例代碼囱晴,一步步來學(xué)習(xí)膏蚓。

二、ajax操作的鏈?zhǔn)綄懛?/p>

jQuery的ajax操作畸写,傳統(tǒng)寫法是這樣的:

$.ajax({

url: "test.html",

success: function(){
      alert("哈哈驮瞧,成功了!");
    },

error:function(){
      alert("出錯啦枯芬!");
    }

});

(運行代碼示例1)

在上面的代碼中剧董,$.ajax()接受一個對象參數(shù),這個對象包含兩個方法:success方法指定操作成功后的回調(diào)函數(shù)破停,error方法指定操作失敗后的回調(diào)函數(shù)翅楼。

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery真慢,返回的是XHR對象毅臊,你沒法進行鏈?zhǔn)讲僮鳎蝗绻哂?.5.0版本黑界,返回的是deferred對象管嬉,可以進行鏈?zhǔn)讲僮鳌?/p>

現(xiàn)在,新的寫法是這樣的:

$.ajax("test.html")

.done(function(){ alert("哈哈朗鸠,成功了蚯撩!"); })

.fail(function(){ alert("出錯啦!"); });

(運行代碼示例2)

可以看到烛占,done()相當(dāng)于success方法胎挎,fail()相當(dāng)于error方法。采用鏈?zhǔn)綄懛ㄒ院笠浼遥a的可讀性大大提高犹菇。

三、指定同一操作的多個回調(diào)函數(shù)

deferred對象的一大好處芽卿,就是它允許你自由添加多個回調(diào)函數(shù)揭芍。

還是以上面的代碼為例,如果ajax操作成功后卸例,除了原來的回調(diào)函數(shù)称杨,我還想再運行一個回調(diào)函數(shù)肌毅,怎么辦?

很簡單姑原,直接把它加在后面就行了悬而。

$.ajax("test.html")

.done(function(){ alert("哈哈,成功了页衙!");} )

.fail(function(){ alert("出錯啦!"); } )

.done(function(){ alert("第二個回調(diào)函數(shù)阴绢!");} );

(運行代碼示例3)

回調(diào)函數(shù)可以添加任意多個店乐,它們按照添加順序執(zhí)行。

四呻袭、為多個操作指定回調(diào)函數(shù)

deferred對象的另一大好處眨八,就是它允許你為多個事件指定一個回調(diào)函數(shù),這是傳統(tǒng)寫法做不到的左电。

請看下面的代碼廉侧,它用到了一個新的方法$.when():

$.when($.ajax("test1.html"), $.ajax("test2.html"))

.done(function(){ alert("哈哈,成功了篓足!"); })

.fail(function(){ alert("出錯啦段誊!"); });

(運行代碼示例4)

這段代碼的意思是,先執(zhí)行兩個操作$.ajax("test1.html")和$.ajax("test2.html")栈拖,如果成功了连舍,就運行done()指定的回調(diào)函數(shù);如果有一個失敗或都失敗了涩哟,就執(zhí)行fail()指定的回調(diào)函數(shù)索赏。

五、普通操作的回調(diào)函數(shù)接口(上)

deferred對象的最大優(yōu)點贴彼,就是它把這一套回調(diào)函數(shù)接口潜腻,從ajax操作擴展到了所有操作。也就是說器仗,任何一個操作----不管是ajax操作還是本地操作融涣,也不管是異步操作還是同步操作----都可以使用deferred對象的各種方法,指定回調(diào)函數(shù)精钮。

我們來看一個具體的例子暴心。假定有一個很耗時的操作wait:

var wait = function(){

var tasks = function(){

alert("執(zhí)行完畢!");

};

setTimeout(tasks,5000);

};

我們?yōu)樗付ɑ卣{(diào)函數(shù)杂拨,應(yīng)該怎么做呢专普?

很自然的,你會想到弹沽,可以使用$.when():

$.when(wait())

.done(function(){ alert("哈哈檀夹,成功了筋粗!"); })

.fail(function(){ alert("出錯啦!"); });

但是炸渡,有一個問題娜亿。$.when()的參數(shù)只能是deferred對象,所以必須對wait進行改寫:

var dtd = $.Deferred(); // 新建一個deferred對象

var wait = function(dtd){

var tasks = function(){

alert("執(zhí)行完畢蚌堵!");

dtd.resolve(); // 改變deferred對象的執(zhí)行狀態(tài)

};

setTimeout(tasks,5000);

return dtd.promise();

};

這里有兩個地方需要注意买决。

首先,最后一行不能直接返回dtd吼畏,必須返回dtd.promise()督赤。原因是jQuery規(guī)定,任意一個deferred對象有三種執(zhí)行狀態(tài)----未完成泻蚊,已完成和已失敗躲舌。如果直接返回dtd,$.when()的默認(rèn)執(zhí)行狀態(tài)為"已完成"性雄,立即觸發(fā)后面的done()方法没卸,這就失去回調(diào)函數(shù)的作用了。dtd.promise()的目的秒旋,就是保證目前的執(zhí)行狀態(tài)----也就是"未完成"----不變约计,從而確保只有操作完成后,才會觸發(fā)回調(diào)函數(shù)迁筛。

其次病蛉,當(dāng)操作完成后,必須手動改變Deferred對象的執(zhí)行狀態(tài)瑰煎,否則回調(diào)函數(shù)無法觸發(fā)铺然。dtd.resolve()的作用,就是將dtd的執(zhí)行狀態(tài)從"未完成"變成"已完成"酒甸,從而觸發(fā)done()方法魄健。

最后別忘了,修改完wait之后插勤,調(diào)用的時候就必須直接傳入dtd參數(shù)沽瘦。

$.when(wait(dtd))

.done(function(){ alert("哈哈,成功了农尖!"); })

.fail(function(){ alert("出錯啦析恋!"); });

(運行代碼示例5)

六、普通操作的回調(diào)函數(shù)接口(中)

除了使用$.when()為普通操作添加回調(diào)函數(shù)盛卡,還可以使用deferred對象的建構(gòu)函數(shù)$.Deferred()助隧。

這時,wait函數(shù)還是保持不變滑沧,我們直接把它傳入$.Deferred():

$.Deferred(wait)

.done(function(){ alert("哈哈并村,成功了巍实!"); })

.fail(function(){ alert("出錯啦!"); });

(運行代碼示例6)

jQuery規(guī)定哩牍,$.Deferred()可以接受一個函數(shù)作為參數(shù)棚潦,該函數(shù)將在$.Deferred()返回結(jié)果之前執(zhí)行。并且膝昆,$.Deferred()所生成的Deferred對象將作為這個函數(shù)的默認(rèn)參數(shù)丸边。

七、普通操作的回調(diào)函數(shù)接口(下)

除了上面兩種方法以外荚孵,我們還可以直接在wait對象上部署deferred接口妹窖。

var dtd = $.Deferred(); // 生成Deferred對象

var wait = function(dtd){

var tasks = function(){

alert("執(zhí)行完畢!");

dtd.resolve(); // 改變Deferred對象的執(zhí)行狀態(tài)

};

setTimeout(tasks,5000);

};

dtd.promise(wait);

wait.done(function(){ alert("哈哈处窥,成功了嘱吗!"); })

.fail(function(){ alert("出錯啦玄组!"); });

wait(dtd);

(運行代碼示例7)

這里的關(guān)鍵是dtd.promise(wait)這一行滔驾,它的作用就是在wait對象上部署Deferred接口。正是因為有了這一行俄讹,后面才能直接在wait上面調(diào)用done()和fail()哆致。

八、小結(jié):deferred對象的方法

前面已經(jīng)講到了deferred對象的多種方法患膛,下面做一個總結(jié):

(1)$.Deferred()生成一個deferred對象摊阀。
  (2)deferred.done()指定操作成功時的回調(diào)函數(shù)
 ∽俚拧(3)deferred.fail()指定操作失敗時的回調(diào)函數(shù)
 “恕(4)deferred.promise()沒有參數(shù)時,作用為保持deferred對象的運行狀態(tài)不變跃捣;接受參數(shù)時漱牵,作用為在參數(shù)對象上部署deferred接口。
 【纹帷(5)deferred.resolve()手動改變deferred對象的運行狀態(tài)為"已完成"酣胀,從而立即觸發(fā)done()方法。
 ∪⑵浮(6)$.when()為多個操作指定回調(diào)函數(shù)闻镶。
除了這些方法以外,deferred對象還有三個重要方法丸升,上面的教程中沒有涉及到铆农。
  (7)deferred.then()
有時為了省事狡耻,可以把done()和fail()合在一起寫顿涣,這就是then()方法波闹。
  $.when($.ajax( "/main.php" ))
  .then(successFunc, failureFunc );
如果then()有兩個參數(shù),那么第一個參數(shù)是done()方法的回調(diào)函數(shù)涛碑,第二個參數(shù)是fail()方法的回調(diào)方法精堕。如果then()只有一個參數(shù),那么等同于done()蒲障。
 〈趼ā(8)deferred.reject()
這個方法與deferred.resolve()正好相反,調(diào)用后將deferred對象的運行狀態(tài)變?yōu)?已失敗"揉阎,從而立即觸發(fā)fail()方法庄撮。
  (9)deferred.always()
這個方法也是用來指定回調(diào)函數(shù)的毙籽,它的作用是洞斯,不管調(diào)用的是deferred.resolve()還是deferred.reject(),最后總是執(zhí)行坑赡。
  $.ajax( "test.html" )
  .always( function() { alert("已執(zhí)行烙如!");} );

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市毅否,隨后出現(xiàn)的幾起案子亚铁,更是在濱河造成了極大的恐慌,老刑警劉巖螟加,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徘溢,死亡現(xiàn)場離奇詭異,居然都是意外死亡捆探,警方通過查閱死者的電腦和手機然爆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黍图,“玉大人曾雕,你說我怎么就攤上這事〈朴纾” “怎么了翻默?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恰起。 經(jīng)常有香客問我修械,道長,這世上最難降的妖魔是什么检盼? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任肯污,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹦渣。我一直安慰自己哄芜,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布柬唯。 她就那樣靜靜地躺著认臊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锄奢。 梳的紋絲不亂的頭發(fā)上失晴,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音拘央,去河邊找鬼涂屁。 笑死,一個胖子當(dāng)著我的面吹牛灰伟,可吹牛的內(nèi)容都是我干的拆又。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼栏账,長吁一口氣:“原來是場噩夢啊……” “哼帖族!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起发笔,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤盟萨,失蹤者是張志新(化名)和其女友劉穎凉翻,沒想到半個月后了讨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡制轰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年前计,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垃杖。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡男杈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出调俘,到底是詐尸還是另有隱情伶棒,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布彩库,位于F島的核電站肤无,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏骇钦。R本人自食惡果不足惜宛渐,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窥翩,春花似錦业岁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仗岸,卻和暖如春糊闽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背爹梁。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工右犹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姚垃。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓念链,卻偏偏與公主長得像,于是被迫代替她去往敵國和親积糯。 傳聞我的和親對象是個殘疾皇子掂墓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 一、什么是deferred對象看成? 開發(fā)網(wǎng)站的過程中君编,我們經(jīng)常遇到某些耗時很長的javascript操作。其中川慌,既有...
    你為什么無理取鬧閱讀 399評論 0 4
  • 源代碼 deffered的使用說明() ajax的使用 運行代碼示例在上面的代碼中吃嘿,$.ajax()接受一個對象參...
    YAMI_1d00閱讀 408評論 0 0
  • jQuery的deferred對象詳解 作者:阮一峰 一、什么是deferred對象梦重? 開發(fā)網(wǎng)站的過程中兑燥,我們經(jīng)常...
    JamHsiao_aaa4閱讀 318評論 0 0
  • jQuery的deferred對象詳解 作者: 阮一峰 日期: 2011年8月16日 jQuery的開發(fā)速度很快...
    nico1988閱讀 1,554評論 0 1
  • 最近做項目,調(diào)用后端接口琴拧,需要等到2個ajax返回再執(zhí)行另一個ajax降瞳,首先想到的是使用promise,但是考慮...
    晴天小豬L閱讀 499評論 0 0