近日做內部推薦項目,在進入項目首頁時,需要進行預調用接口判斷,按照以往的習慣,應該將調用接口后執行的代碼,放入ajax請求success內執行。這樣當然可以,但是代碼組織和可讀性都沒有那么高。通過查看[Jquery官網api](http://api.jquery.com/category/deferred-object/)發現了deferred object(延遲對象)這個概念。
**一、API文檔的翻譯:**
延遲對象,在jquery1.5被引入,是調用jQuery.Deferred()方法生成的一個鏈式功用對象。它可以注冊多個回調到回調隊列,提取回調隊列,傳遞任何異步或同步函數的成功或失敗狀態。
延遲對象是一個鏈式的,類似于jquery對象的鏈式,但是它有自己的方法。在創建之后,你可以用任何下面涉及到的方法,無論是直接鏈式調用,還是保存這個對象到變量,并在這個變量上調用一個或多個方法。
- **deferred.always()**
**添加操作方法,不管延遲對象是處于解決狀態還是拒絕狀態都被調用。**
- **deferred.done()**
**添加操作方法,只有延遲對象處于已解決狀態才被調用**
- **deferred.fail()**
**添加操作方法,只有延遲對象處于被拒絕狀態才會被調用**
- **deferred.isRejected()**
**判斷一個延遲對象是否處于被拒絕狀態**
- **deferred.isResolved()**
**判斷一個延遲對象是否處于已解決狀態。**
- **deferred.notify()**
**調用一個給定變量的延遲對象上的進行中的回調。**
- **deferred.notifyWith()**
**調用一個給定變量和上下文的延遲對象上的進行中的回調。**
- **deferred.pipe()**
**用來過濾and或or鏈式延遲的效用方法**
- **deferred.progress()**
**當延遲對象生成進行中通知時,添加操作被調用。**
- **deferred.promise()**
**返回延遲允諾對象。**
- **deferred.reject()**
**拒絕一個延遲對象并且調用任何給定參數的失敗回調。**
- **deferred.rejectWith()**
**拒絕回調對象,調用任何給定上下文和參數的失敗回調。**
- **deferred.resolve()**
**解決一個延遲對象,并且調用任何給定參數的完成回調。**
- **deferred.resolveWith()**
**解決一個延遲對象,并且調用任何給定上下文和參數的完成回調。**
- **deferred.state()**
**判斷當前延遲對象狀態。**
- **deferred.then()**
**當延遲對象被解決、拒絕或進行中添加方法被調用。**
- **jQuery.Deferred()**
**延遲對象的構造函數。**
- **jQuery.when()**
**提供一個方法執行基于一個或多個對象的回調函數,回調函數經常是代表異步事件的延遲對象**
- **.promise()**
**當所有的綁定到集合、隊列或沒有的動作被完成返回一個promise對象。**
**二、延遲對象分析與使用:**
**不難得出結論,以上API包括了延遲對象的構建、延遲狀態設定方法、延遲狀態監聽方法。**
****
**延遲對象的數據結構**
延遲對象包括三種狀態:resolved(已解決)、rejected(未解決)、progress(進行中)。這三種狀態可以用延遲對象state方法實時查看。
****
**延遲對象狀態查看**
延遲對象是jquery的回調函數解決方案,延遲顧名思義就是延遲到未來某個點再執行,類似jquery動畫函數中delay方法,區別在于后者是延遲固定時間,延遲對象則是通過固定狀態判斷延遲執行的時機。
~~~
var dtd = $.Deferred(); // 新建一個deferred對象
var wait = function(dtd){
var tasks = function(){
alert("執行完畢!");
dtd.resolve(); // 改變deferred對象的執行狀態
};
setTimeout(tasks,5000);
return dtd;
};
$.when(wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯啦!"); });
~~~
**上述代碼執行流程圖:**
****
?上述代碼例子,延遲對象定義為一個全局對象,這樣就會造成延遲狀態,可以在任何時間進行更改。
**改進的方法一:**
~~~
var dtd = $.Deferred(); // 新建一個Deferred對象
var wait = function(dtd){
var tasks = function(){
alert("執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks,5000);
return dtd.promise(); // 返回promise對象,promise對象只開放與狀態無關的方法,即那三種狀態方法不開放,無法設置
};
var d = wait(dtd); // 新建一個d對象,改為對這個對象進行操作
$.when(d)
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯啦!"); });
d.resolve(); // 此時,這個語句是無效的
~~~
**上述代碼,在wait函數返回值是一個promise對象,由下圖promise對象數據結構不難發現,promise對象擁有除了修改狀態方法以外延遲對象的所有方法,也就是說,promise對象無法改變執行狀態,這樣就能夠防止外界對狀態的更改。**
****
**promise對象的數據結構**
**改進方法二:**
**將延遲對象構建成函數內部的局部變量,這樣更好的實現了封裝,防止外部對狀態進行改變。**
~~~
var wait = function(dtd){
var dtd = $.Deferred(); //在函數內部,新建一個Deferred對象
var tasks = function(){
alert("執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks,5000);
return dtd.promise(); // 返回promise對象
};
$.when(wait())
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯啦!"); });
~~~
**改進方法三:**
直接將函數名作為$.Deferred()參數傳入,$.Deferred()所生成的延遲對象會作為wait函數參數傳入函數。
~~~
var wait = function(dtd){
var tasks = function(){
alert("執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks,5000);
return dtd.promise(); // 返回promise對象
};
$.Deferred(wait)
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯啦!"); });
~~~
****
**$.Deferred()方式執行狀態**
**三、項目使用情況:**
**樂帝在內推項目中使用的是第二種方法,即將延遲對象作為局部變量定義,并返回promise對象。這里promise對象與延遲對象除了不能改變狀態,對延遲狀態的記錄及監聽方法都相同。**
~~~
function loadInternalHost() {
var dtd = $.Deferred();
dtd.resolve();
return dtd.promise();//在原defferred對象上返回另一個deferred對象,兩個對象都會記錄最初deferred對象狀態,但后者不能改變狀態,其他方法一致
}
~~~
****
**promise對延遲狀態的記錄**
**當分別調用兩個接口時,延遲監聽函數允許為多個事件指定一個回調。**
**如下代碼,分別取得內推城市及內推公告兩部分數據后,執行后續加載數據的動作。**
~~~
$.when(getInternalRecommendCitys(), getComment()).done(function () {
getInternalRecommendJobAdList(oldSearchData.keyWord, oldSearchData.locId);
});
function getInternalRecommendCitys() {
var dtd = $.Deferred();
$.ajax({
type: "get",
data: {
"openId": openId
},
dataType: "json",
url: "../api/InternalInfo/InternalRecommendCitys",
success: function (data) {
$city = $("#citySelect");
for (var i = 1; i < data.length; i++) {
$str = $("<option></option>");
$str.text(data[i].name);
$str.val(data[i].value);
$city.append($str);
dtd.resolve();
}//將可選城市導入到選擇列表
},
error: function () {
dtd.resolve();
}
});
return dtd.promise();
}
function getComment() {
var dtd = $.Deferred();
$.ajax({
type: "get",
data: {
"openId": openId
},
dataType: "json",
url: "../api/InternalInfo/GetComment",
success: function (data) {
$(".notice-content pre").html(data.data);
dtd.resolve();
},
error: function () {
dtd.resolve();
}
});//獲取公告數據
return dtd.promise();
}
~~~
- 前言
- 前端編程提高之旅(一)----插件
- 前端編程提高之旅(二)----網站常見特效的jquery實現
- 前端編程提高之旅(三)----瀏覽器兼容之IE6
- 前端編程提高之旅(四)----backbone初體驗
- 前端編程提高之旅(五)----寫給大家看的css書
- 前端編程提高之旅(六)----backbone實現todoMVC
- 前端編程提高之旅(七)----marionette實現todoMVC
- 前端編程提高之旅(八)----D3.js數據可視化data join解析
- 前端編程提高之旅(九)----延遲對象
- 前端編程提高之旅(十)----表單驗證插件與cookie插件
- 前端編程提高之旅(十一)----jquery代碼的組織
- 前端編程提高之旅(十二)----position置入值應用
- 前端編程提高之旅(十三)----jquery選擇器
- 前端編程提高之旅(十四)----jquery DOM操作
- 前端編程提高之旅(十五)----jquery事件
- 前端編程提高之旅(十六)----jquery中的動畫
- 前端編程提高之旅(十七)----jquery中表單、表格和ajax
- 前端編程提高之旅(十八)----移動端web流行交互技術方案研究