javascript 学习笔记之JQuery中的Deferred对象
Deffered是Jquery中的一个非常重要的对象,从1.5版本之后,Jquery中的ajax操作都基于Deffered进行了重构,这个对象的处理模式就像其他Javascript框中的Promise异步模式一样,它代表一个潜在的、长时间运行但不必返回完成操作的结果,与等待并阻塞浏览器进程直到完成操作相比,Deffered返回的是一个承诺异步执行结果的对象,这个承诺可以有返回值,也可以没有,浏览器被释放出来做其他事情,直到这个返回结果被使用到。Deffered的原理是给异步请求过程中状态的变化注册回调函数,实现链式调用,如对象的then函数;统一对这些回调函数的结果进行管理控制,以面对多个请求的需要,如Jquery中的when函数。
下面用一个简单的例子看看Deffered对象是如何工作的:
function BeginRequest() {
//定义deferred对象
var def = $.Deferred();
//创建XMLHttpRequest对象
var request = new XMLHttpRequest();
//配置一个异步请求
request.open("GET", "../textPage/httpScript.ashx");
//定义请求状态变化的处理过程
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
def.resolve(request.responseText);
}
else if (request.status === 404) {
def.reject();
}
}
//设置请求头
request.setRequestHeader("content-type", "text/plain");
//开启一个请求
request.send(null);
//返回deferred对象
return def;
}
我们先通过JQuery中的Deferred()函数创建一个deferred对象,然后在异步请求中根据请求的状态分别注册对象的resolve和reject函数,最后返回这个deferred对象,接下来可以进行链式调用:
BeginRequest().then(function(s) {
console.log("success.");
}, function() {
console.log("failed.");
});
上面调用了deferred对象的then函数,这个函数有两个函数参数,第一个是异步结果成功的时候执行,第二个是失败的时候执行。
这里需要介绍一下deferred对象的三种执行状态:未完成、已完成、已失败。如果是已完成(resolve),deferred对象会立即触发done()函数指定的回调函数;如果是已失败(reject),deferred对象会立即触发fail()函数指定的回调函数;如果是未完成,即等待过程中,则继续等待或者deferred对象触发process()(jquery1.7版本及以上)函数指定的回调函数。上面的then函数传递了两个回调函数分别对完成和失败两种状态进行处理,而且deferred对象的状态可以通过调用对象中resolve()和reject()函数改变,调用分别触发done()和fail()指定的回调函数,故上述调用部分可以改写为:
BeginRequest().done(function(s) {
console.log("success.");
}).fail(function() {
console.log("failed.");
});
可以看出,deferred对象的引入给程序的异步执行带来了极大的便利,更加简洁,可读性更高。这在JQuery Ajax请求中得到了及普遍的应用,在1.5版本以前,Ajax请求返回的是XHR对象,其成功及差错处理方式如下:
$.ajax({
//要请求的url
url: "../textPage/httpScript.ashx",
//请求成功后调用的回调函数
success: function(result) {
console.log("success.");
},
//请求失败后调用的回调函数
error: function(e) {
console.log("failed.");
}
});
传统的ajax请求接收一个无类型对象为参数,对象中指定了请求的url及回调函数,当回调过程中嵌套ajax请求的话,这个过程看起来很不清晰。在1.5及以后的版本中,ajax返回的对象不再是XHR类型,而是deferred对象,且会自动触发其状态的改变,故新的ajax请求可以改写为:
$.ajax("../textPage/httpScript.ashxs").then(function() {
console.log("success.");
}, function() {
console.log("failed.");
});
这里使用了then方法,当然,也可以调用fail和done函数实现。
上面对JQuery中deferred对象的使用有了初步的了解,接下来进行进一步学习:
deferred对象的作用范围
正是因为deferred的状态可以通过其对象调用resolve和reject函数来动态改变,所以在程序流程中我们不希望其状态被意外的改变而造成错误,下面代码是很好的证明:
function BeginRequest() {
//定义deferred对象
var def = $.Deferred();
//创建XMLHttpRequest对象
var request = new XMLHttpRequest();
//配置一个异步请求
request.open("GET", "../textPage/httpScript.ashx");
//定义请求状态变化的处理过程
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
//正常处理过程被延时5秒钟
setTimeout(function() {
def.resolve("the request is complete.");
}, 5000);
}
else if (request.status === 404) {
def.reject();
}
}
//设置请求头
request.setRequestHeader("content-type", "text/plain");
//开启一个请求
request.send(null);
//返回deferred对象
return def;
} //保存异步操作结果的deferred对象,以作他用
var tempDef = BeginRequest().done(
function(msg) {
if (arguments.length <= 0) {
//如果是意外改变
console.log("valid call.");
}
else {
//成功后改变
console.log(msg);
}
}).fail(
function() {
console.log("failed.");
});
//意外改变deferred的状态为已完成
tempDef.resolve();
代码中将请求成功后的执行过程人为的延迟了5秒,以模仿耗时操作,在调用的时候保存了deferred对象以备他用,但是程序意外的通过这个被保存的对象更改了其状态,执行上面的代码,输出”valid call“而不是”the request is complete .“。
可见,deferred对象的直接传递存在一定的安全和不确定的风险,为了避免这种情况,有三种方式可以解决:
1. 尽量在同一个函数或者模块中使用deferred对象及其相关操作。
2. 在使用deferred对象时尽量使用链式调用,不要暴露传递中的deferred对象给其他模块。
3. 为此,JQuery专门为deferred定义了一个promise方法,该方法也返回一个deferred对象,但这个对象不再包含引起状态改变的函数,如:resolve、reject、resolveWith等,这种方式最优。
对于JQuery中的Promise函数,我的理解是为了保持异步执行状态,防止不确定状态改变而定义的。借上例,我们将BeginRequest()函数的最后一行改写为:
1 //返回deferred的安全对象
2 return def.promise();
如此,再次执行上面的过程,程序果断抛出异常:
5秒后输出正常路径下的结果,可见,deferred对象的状态没有被改变。这里有一篇很好的文章,可以参考一下。
同一个异步操作指定多个回调函数
也就是说,在异步操作返回的deferred对象上可以绑定多个回调函数(done、fail、then均可),幸运的是:done、fail、then函数返回的都是对同一个deferred对象的引用,故可以对同一个deferred对象执行多个done(或者fail或者then)处理过程,这些处理过程一次顺序执行,以done为例,代码如下:
$.ajax("../textPage/httpScript.ashxs")
.done(function() {
console.log("success.");
})
.done(function() {
console.log("第二次处理.");
})
.done(function() {
console.log("第三次处理");
});
//……
大部分实际需求均不会如此使用,但对于流程性比较强的处理过程,可以如此来分步执行,使实现过程更加简洁,特别是在动画处理的过程中。
大多数时候,我们只需要在done的回调函数中执行响应处理操作即可,但是偶尔需要针对不同的情况作出不同的处理,如何做呢?嗯,其实done等异步处理函数中指定的回调函数是可以添加参数的,单个异步请求中,回调函数有三个参数
,第一个参数是异步结果,第二个对象是请求状态,第三个是结果的deferred对象,代码如下:
$.ajax("../textPage/httpScript.ashx")
//成功时执行此回调函数
.done(
function(result, status, def) {
console.log(result.toString());
console.log(status.toString());
console.log(typeof def);
}
)
//失败时执行此回调函数
.fail(
function(result, status, def) {
console.log("failed.");
}
);
输出如下:
为多个异步操作指定统一的回调处理
在实际需求中,我们会遇到很多异步操作,如果业务逻辑要求在某些异步操作均完成后再进行其他操作,那么我们需要对这些异步操作进行等待,直到所有都完成,即为多个异步操作定义统一的回调函数来对成功和失败进行管理,传统的异步方法是做不到的。在JQuery中,when函数可以很好的很方便的解决这一问题,来看下面的代码:
$.when($.ajax("../textPage/httpScript.ashx"), $.ajax("../textPage/Pictrue.aspx"))
//成功时执行此回调函数
.done(
function() {
console.log("success.")
}
)
//失败时执行此回调函数
.fail(
function() {
console.log("failed.");
}
);
$.when()函数返回的是deferred对象,故上面对该返回值用函数done()、fail()分别处理成功及失败的情况(then函数也可以实现),和其他不同的是when函数中我们执行了两个异步请求,它的执行过程须等待所有起步请求执行完毕,才能进行done或者fail的处理流程,并且,只有当when函数中的所有异步操作均成功才能触发done函数中指定的回调函数,其中一个或者多个失败则会触发fail函数中指定的回调函数。
有趣的是,我们可以在done或者fail中进行详细跟踪每个请求的结果,这需要对done和fail中定义的回调函数添加参数,改写如下:
$.when($.ajax("../textPage/httpScript.ashx"), $.ajax("../textPage/Pictrue.aspx"))
//成功时执行此回调函数
.done(
function(r1, r2) {
console.log("success.")
}
)
//失败时执行此回调函数
.fail(
function(r1, r2) {
console.log("failed.");
}
);
经过测试,发现上述阴影部分所标记的参数分别代表when中每个请求的结果对象,对这些参数进行监控调试,其内容如下:
由上图可以看出,r1和r2均是长度为3的数组,以r1为例,数组的第一个元素是异步操作的结果,第二个元素是异步操作状态,第三个元素是当前异步操作返回的deferred结果对象。经验证,r1和r2分别是then中两个请求的结果对象,如此我们在为多个异步操作统一回调函数的同时,也可以根据不同操作的返回结果给用户以不同的反馈,这可以通过给回调函数添加参数获得。
不局限于异步ajax请求
JQuery中的deferred对象不仅应用于ajax异步请求,对于一些复杂耗时的脚本操作也是可以的,它提供了对异步操作结果的一个将来结果,用以对异步操作的一个管理,查看下面的 代码:
var handle = function() {
//创建deferred对象
var def = $.Deferred();
//内部函数
function test() {
alert("over.");
//改变执行状态
def.resolve();
}
//模仿某个复杂耗时的操作,模拟需要5秒,然后再执行函数test
setTimeout("test()", 5000);
//返回deferred对象;
return def.promise();
} $.when(handle)
.done(
function() {
console.log("success.");
}
)
.fail(
function() {
console.log("failed.");
}
);
总结:JQuery中的deferred对象为了js脚本的异步过程提供了一种结果处理方式,它不改变原有的异步过程,以更加简洁、更加易读的方式管理并执行异步操作,从原理上来说,只是更加完善的完成异步操作而已。
javascript 学习笔记之JQuery中的Deferred对象的更多相关文章
- jQuery学习笔记(二)jQuery中DOM操作
目录 DOM操作分类 jQuery中的各种DOM操作 查找节点 创建节点 删除节点 复制节点 替换节点 包裹节点 属性操作 样式操作 对HTML.文本和值的操作 遍历节点 CSS-DOM操作 小结 本 ...
- jQuery中的deferred对象和extend方法
1⃣️deferred对象 deferred对象是jQuery的回调函数解决方案,它是从jQuery1.5.0版本开始引入的功能 deferred对象的方法 (1) $.Deferred() 生成一个 ...
- MongoDB学习笔记~MongoDB实体中的值对象
回到目录 注意,这里说的值对象是指在MongoDB实体类中的,并不是DDD中的值对象,不过,两者也是联系,就是它是对类的补充,自己本身没有存在的价值,而在值对象中,也是不需要有主键Id的,这与DDD也 ...
- JavaScript学习笔记(四)——jQuery插件开发与发布
jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...
- 【学习笔记】jQuery中的动画与效果
1.基本效果 匹配元素从左上角开始变浓变大或缩小到左上角变淡变小 ①隐藏元素 除了可以设置匹配元素的display:none外,可以用以下函数 hide(speed,[callback]) 返回值: ...
- jQuery学习笔记(9)--jquery中的事件--$(document).ready()
1.$(document).ready()方法是事件模块中最重要的一个函数,可以极大地提高web应用程序的相应速度. 2.执行时机:DOM就绪后就会执行,而javascript中window.onlo ...
- web前端学习(四)JavaScript学习笔记部分(4)-- JavaScriptDOM对象
1.Javascript-DOM简介 1.1.HTML DOM 1.2.DOM操作HTML 1.2.1.JavaScript能够改变页面中的所有HTML元素 1.2.2.JavaScript能够改变页 ...
- javascript学习笔记(八):浏览器对象
window对象 <!DOCTYPE html> <html> <head lang="en"> <meta chaset="U ...
- 廖雪峰 JavaScript 学习笔记(字符串、数组和对象)
字符串 1.和python一样,也是用' '或" "括起来的字符表示.但多行字符串是用反引号(esc下键)``,与之相对的是Python用''' '''三引号表示: 2.转义字符: ...
随机推荐
- [ZETCODE]wxWidgets教程三:第一个窗体程序
本教程原文链接:http://zetcode.com/gui/wxwidgets/firstprograms/ 翻译:瓶哥 日期:2013年11月27日星期三 邮箱:414236069@qq.com ...
- 研磨设计模式解析及python代码实现——(一)简单工厂模式
最近在学设计模式,正巧书之前学了些python,但用的还不是很成熟.<研磨设计模式>书上只给了java代码,本着以练手为目标,我照着书上打了一遍java代码,在仔细体会其思想后,将其写成了 ...
- IoC/DIP其实是一种管理思想
关于IoC的的概念提出来已经很多年了,其被用于一种面象对像的设计.我在这里再简单的回顾一下这个概念.我先谈技术,再说管理. 话说,我们有一个开关要控制一个灯的开和关这两个动作,最常见也是最没有技术含量 ...
- HDU 2298 Toxophily
题目: Description The recreation center of WHU ACM Team has indoor billiards, Ping Pang, chess and bri ...
- equals()和hashCode()区别?
equals()和hashCode()区别? ------------------------------------------------- equals():反映的是对象或变量具体的值,即两个对 ...
- 用LINQPad加上Tx驱动来分析log
Tx (LINQ to Logs and Traces)是微软发布的开源工具.可以用这个工具来使用LINQ分析日志,包括 Event Tracing for Windows (ETW) Event L ...
- iOS 开发中常见的设计模式
最近有小伙伴问到在iOS开发中的几种设计模式,这里摘录一下别人的总结(因为已经感觉总结得差不多了,适用的可以阅读一下) 首先是开发中的23中设计模式分为三大类:1.创建型 2.结构型 3.行为型 (i ...
- 【设计模式 - 21】之空对象模式(Null Object)
1 模式简介 在空对象模式中,一个空对象取代NULL对象的实例的检查.NULL对象不是检查空值,而是反映一个不做任何动作的关系.这样的NULL对象也可以在数据不可用的时候提供默认的行为. 在 ...
- Java_Web 连接池
对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式正是为了解决资源的频繁分配﹑释放所造成的问题.为解决我们的问题,可以采用数据库连接池技术.数据库连接池的基本思想就是为 ...
- 国外NET 空间免费申请使用
最近研究微信公众帐号接口开发,需要使用到域名和空间,所以在度娘和谷哥的帮助下找到国外免费的空间, 刚刚注册完所以截图和大家分享下 注册地址:http://member.mywindowshosting ...