異步方式的概述
- 通過事件達(dá)到異步操作
- 通過我們最熟悉的回調(diào)
- 類promise的方式
首先我們注意到1.5版本前后的jquery有一個(gè)重要的不同
//before 1.5
var option={
type:'GET',
url:'...',
success:function(){..},
fail:function(){..},
complete:function(){..}
};
$.ajax(option);
//after 1.5
$.ajax(option)
.done(function(){..})
.fail(function(){..})
.progress(function(){..})
.always(function(){..})
1.5版本之后變成了優(yōu)美的鏈?zhǔn)秸{(diào)用,并且可以對(duì)同一事件增加多個(gè)回調(diào)函數(shù)妖碉,原因是原生的xhr對(duì)象換成了jqxhr對(duì)象,里面有什么魔法呢推溃?
從promise講起
promise在javascript編程世界里可以說是大名鼎鼎截粗,下面這段代碼給出了它的簡單用法巨税。
promise(function(){..}).
then([successhandler1,successhandler2,..],
[failhandler1,failhandler2,...]);
promise為我們呈現(xiàn)出了異步編程的一種新模式疫稿,但它還不夠漂亮培他,接下來我們看一看jQuery引入的deferred。
jQuery的Deferred
創(chuàng)建Deferred對(duì)象
var de=$.Deferred();//空的Deferred對(duì)象
$.Deferred(function(){..}).
done(function(){..});
//會(huì)直接執(zhí)行里面的function并返回一個(gè)Deferred對(duì)象
function tmp(defer){
....
return defer;
};//這個(gè)寫法的含義我們留在后面再講
Deferred的機(jī)理
我們可以這樣想遗座,每個(gè)deferred對(duì)象內(nèi)部有一個(gè)隱藏著的狀態(tài)變量舀凛,有成功、失敗员萍、執(zhí)行中三種狀態(tài)腾降,當(dāng)程序執(zhí)行成功則會(huì)把它設(shè)為成功,否則設(shè)為失敗碎绎。這里的成功失敗指的是滿足某種設(shè)定條件,并非一般意義上的出錯(cuò)抗果,即使拋出異常也不認(rèn)為其失敗筋帖。我們可以在程序的運(yùn)行過程中根據(jù)檢測到的狀態(tài)來決定之后哪些回調(diào)函數(shù)會(huì)被執(zhí)行。
設(shè)定狀態(tài)實(shí)例
$(function(){
....
if(..) this.resolve(arg1,arg2,..);
//會(huì)執(zhí)行done和always回調(diào)冤馏,args是傳入回調(diào)的參數(shù)
//同類函數(shù)this.resolveWith(content,[args..]);content作為回調(diào)函數(shù)中的this
else this.reject(arg1,arg2,..);
//執(zhí)行fail和always回調(diào)日麸,rejectWith基本同上
//需要注意的是always也必須狀態(tài)改變才能調(diào)用,若一直處于執(zhí)行狀態(tài),也不會(huì)調(diào)用
....
this.notify(args);//調(diào)用progress回調(diào)代箭,但必須在狀態(tài)變?yōu)槌晒蚴∏鞍l(fā)起墩划,這里progress不會(huì)被調(diào)用
//notifyWith基本同上
}).fail(..).done(..).progress(..);
還需要注意的是,即使?fàn)顟B(tài)發(fā)生改變了嗡综,程序還會(huì)繼續(xù)運(yùn)行乙帮。這里所說的成功失敗指的是滿足我們?cè)O(shè)定的條件與否,和程序真的運(yùn)行狀態(tài)無關(guān)极景,done察净、fail、always返回的依然是原本的deferred對(duì)象盼樟。
請(qǐng)記住無論什么回調(diào)都是在函數(shù)執(zhí)行完后調(diào)用氢卡,函數(shù)執(zhí)行不會(huì)被中斷
最后還要注意一點(diǎn)未防止?fàn)顟B(tài)在程序外部被更改,應(yīng)該加上一句
$.Deferred(function(){..}).promise().done(..).fail(..);
但promise返回的不再是原本的Deferred對(duì)象了晨缴,也不能在外部更改其狀態(tài)了译秦。
強(qiáng)勁的when
看到這里我們可能有一個(gè)疑問,如果我們有一系列任務(wù)來決定后來的回調(diào)怎么辦击碗,不用擔(dān)心我們有when筑悴。
$.when(defer1,defer2...);
//這時(shí)候如果每個(gè)defer還要$(func(){..})就很難寫了,所以就回到我們開始介紹的最后一種延都,利用函數(shù)返回
var defer1=$.Deferred();
var defer2=$.Deferred();
function func1(defer){...return defer;}
function func2(defer){...return defer;}
$.when(func1(defer1),func2(defer2)).done(..).fail(..);
//當(dāng)全部defer成功done才會(huì)被調(diào)用雷猪,有一個(gè)defer失敗fail就會(huì)調(diào)用,但無論怎樣一個(gè)回調(diào)函數(shù)最多被調(diào)用一次晰房,且不會(huì)影響所有函數(shù)的執(zhí)行
var tmp=9;
$.when(tmp).done(..).fail(..);
//當(dāng)when鏈里面全部不是defer變量時(shí)會(huì)直接執(zhí)行done回調(diào)求摇,注意是全部,有defer變量會(huì)跳過非defer殊者,回調(diào)取決于defer