一、deferred對象的含義
? ? 在以往過程中,我們想要在異步操作或耗時(shí)較長的同步操作完成后執(zhí)行某操作,這時(shí)我們往往會采取回調(diào)的方式進(jìn)行解決。如果進(jìn)行了多次回調(diào)操作會導(dǎo)致代碼復(fù)雜且難維護(hù),而jQuery中的deferred對象就是可以解決這種問題,總的來說deferred對象就是jQuery的回調(diào)函數(shù)解決方案。這也讓我聯(lián)想到了ES6的promise對象也有這樣的作用,下面我也會適當(dāng)?shù)睾虴S6的promise對象進(jìn)行類比。
二、deferred對象實(shí)戰(zhàn)
? ? 下面直接上代碼。
????var dtd = $.Deferred(); // 新建一個(gè)deferred對象 相當(dāng)于ES6的 new Promise()
var wait = function(dtd){
var tasks = function(){
alert("執(zhí)行完畢!");
? ? ? ? ? ? ? ? ? ? ??dtd.resolve();?// 改變deferred對象的執(zhí)行狀態(tài) 相當(dāng)于ES6的 promise.resolve()
};
setTimeout(tasks,5000);
? ?????????????return dtd;
};
現(xiàn)在,wait()函數(shù)返回的是deferred對象,這就可以加上鏈?zhǔn)讲僮髁恕?/p>
$.when(wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯(cuò)啦!"); });
運(yùn)行結(jié)果為:5秒后輸出"執(zhí)行完畢!",然后再輸出"哈哈,成功了!"
上面有一個(gè)問題就是??var dtd = $.Deferred()中的dtd是一個(gè)全局對象,可以在全局中改變它的狀態(tài),例如:
$.when(wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯(cuò)啦!"); });
? ??????dtd.resolve();
這就改變了dtd對象的執(zhí)行狀態(tài),因此導(dǎo)致done()方法立刻執(zhí)行,跳出"哈哈,成功了!"的提示框,等5秒之后再跳出"執(zhí)行完畢!"的提示框
為了避免這種情況,jQuery提供了deferred.promise()方法。它的作用是,在原來的deferred對象上返回另一個(gè)deferred對象,后者只開放與改變執(zhí)行狀態(tài)無關(guān)的方法(比如done()方法和fail()方法),屏蔽與改變執(zhí)行狀態(tài)有關(guān)的方法(比如resolve()方法和reject()方法),從而使得執(zhí)行狀態(tài)不能被改變。
以下是推薦的寫法:
var wait = function(dtd){
? ??????var dtd = $.Deferred(); //在函數(shù)內(nèi)部,新建一個(gè)Deferred對象
var tasks = function(){
alert("執(zhí)行完畢!");
dtd.resolve(); // 改變Deferred對象的執(zhí)行狀態(tài)
????????????????};
????????????????setTimeout(tasks,5000);
return dtd.promise(); // 返回promise對象
};
$.when(wait())
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯(cuò)啦!"); });
三、小結(jié)
(1)?$.Deferred()?生成一個(gè)deferred對象。相當(dāng)于ES6的new Promise()
(2)?deferred.done()?指定操作成功時(shí)的回調(diào)函數(shù)
(3)?deferred.fail()?指定操作失敗時(shí)的回調(diào)函數(shù)。相當(dāng)于ES6的Promise.prototype.catch()
(4)?deferred.promise()?沒有參數(shù)時(shí),返回一個(gè)新的deferred對象,該對象的運(yùn)行狀態(tài)無法被改變;接受參數(shù)時(shí),作用為在參數(shù)對象上部署deferred接口。
(5)?deferred.resolve()?手動改變deferred對象的運(yùn)行狀態(tài)為"已完成",從而立即觸發(fā)done()方法。相當(dāng)于ES6的Promise.resolve()
(6)deferred.reject()?這個(gè)方法與deferred.resolve()正好相反,調(diào)用后將deferred對象的運(yùn)行狀態(tài)變?yōu)?已失敗",從而立即觸發(fā)fail()方法。相當(dāng)于ES6的Promise.reject()
(7)?$.when()?為多個(gè)操作指定回調(diào)函數(shù)。相當(dāng)于ES6的Promise.all()
(8)deferred.then()有時(shí)為了省事,可以把done()和fail()合在一起寫,這就是then()方法。$.when($.ajax( "/main.php" )).then(successFunc, failureFunc )。相當(dāng)于ES6的Promise.prototype.then()
(9)deferred.always()? 這個(gè)方法也是用來指定回調(diào)函數(shù)的,它的作用是,不管調(diào)用的是deferred.resolve()還是deferred.reject(),最后總是執(zhí)行。相當(dāng)于ES6的Promise.prototype.finally()
參考自