近日做内部推荐项目,在进入项目首页时,需要进行预调用接口判断,按照以往的习惯,应该将调用接口后执行的代码,放入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包括了延迟对象的构建、延迟状态设定方法、延迟状态监听方法。**
**![](https://box.kancloud.cn/2016-02-24_56cd5e44d47d5.jpg)**
**延迟对象的数据结构**
延迟对象包括三种状态:resolved(已解决)、rejected(未解决)、progress(进行中)。这三种状态可以用延迟对象state方法实时查看。
**![](https://box.kancloud.cn/2016-02-24_56cd5e4508190.jpg)**
**延迟对象状态查看**
延迟对象是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("出错啦!"); });
~~~
**上述代码执行流程图:**
**![](https://box.kancloud.cn/2016-02-24_56cd5e451b9c5.jpg)**
上述代码例子,延迟对象定义为一个全局对象,这样就会造成延迟状态,可以在任何时间进行更改。
**改进的方法一:**
~~~
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对象无法改变执行状态,这样就能够防止外界对状态的更改。**
**![](https://box.kancloud.cn/2016-02-24_56cd5e452c4d9.jpg)**
**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("出错啦!"); });
~~~
**![](https://box.kancloud.cn/2016-02-24_56cd5e453f18c.jpg)**
**$.Deferred()方式执行状态**
**三、项目使用情况:**
**乐帝在内推项目中使用的是第二种方法,即将延迟对象作为局部变量定义,并返回promise对象。这里promise对象与延迟对象除了不能改变状态,对延迟状态的记录及监听方法都相同。**
~~~
function loadInternalHost() {
var dtd = $.Deferred();
dtd.resolve();
return dtd.promise();//在原defferred对象上返回另一个deferred对象,两个对象都会记录最初deferred对象状态,但后者不能改变状态,其他方法一致
}
~~~
**![](https://box.kancloud.cn/2016-02-24_56cd5e454fb7b.jpg)**
**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流行交互技术方案研究