$.ajax()引发的对Deferred的总结 (转)
传统的ajax写法:
$.ajax({
url:"1.json",
type:"get",
success:function(data){},
error:function(){}
});
jquery 1.7以后的新写法,
$.ajax({
url:"1.json",
type:"get"
}).done(function(data){ }).fail(function(){ });
我就纳闷了.$.ajax()返回的是XMLHttpRequest对象.
我们都知道XMLHttpRequest是ajax的一个核心对象,用于和服务器交互的,
可是XMLHttpRequest对象根本就没有什么done,fail方法,
这里的方法是怎么加上去的呢?
我们从done入手.在官网api上搜索done.
发现一个Deferred关键词.
我们现在就从jQuery的Deferred开始讲起吧.
Deferred对象是jquery开发团队设计的,为了增强jquery的回调功能,在1.7版本中加入了jquery.
defer英语意思是延迟的意思.那么他是如何延迟的呢?
首先来理解一下基本知识,要不然后面没法说了.
$.Deferred([fun])
$.Deferred()没有参数时 返回Deferred对象;
有参数时,表示在这个参数上做延迟或异步操作,并且返回Deferred对象.
done(fn) 当延迟成功后调用该方法
fail(fn) 当延迟失败时调用失败
then(done,fail) 这个是done和fail的总写方式
always(fn) 不管延迟执行的成功还是失败,都执行的方法
上面的fn可能是一个function,也有可能是多个以逗号分隔的function函数
resolve和reject方法一旦执行,表示开始执行done,fail,then,always方法,
注意Deferred对象可以一次挂接多个done,fail方法,按照你分布的顺序依次执行.
resolve(value) 告诉对象执行done回调,value是参数
reject(value) 告诉对象执行fail回调,value是参数.
调用done回调代码:
var dfd = $.Deferred();
dfd.done(function(value) {
alert(value);
});
dfd.resolve("执行done回调");
调用fail回调代码:
var dfd = $.Deferred();
dfd.done(function(value) {
alert(value);
});
dfd.reject("执行fail回调");
调用then回调代码:
var dfd = $.Deferred();
var doneFun=function(value) {
alert("done:"+value);
};
var failFun=function(value) {
alert("fail:"+value);
}
dfd.then(doneFun,failFun);
dfd.reject("思思博士");
调用always回调代码:
var dfd = $.Deferred();
var doneFun = function(value) {
alert("done:" + value);
};
var failFun = function(value) {
alert("fail:" + value);
}
dfd.then(doneFun, failFun).always(function() {
alert("不管你延迟成功还是失败,我都要执行always.");
});
dfd.resolve("我要执行done,但是这不影响我执行always!");
state() 返回deferred对象目前的状态
1.pending:操作没有完成
2.resolved:操作成功
3.rejected:操作失败
代码:
var dfd=$.Deferred();
dfd.done(function(){
console.log("done");
});
console.log(dfd.state());
dfd.resolve();
console.log(dfd.state());
上面我们说了:resolve表示立马执行回调,
所以这个地方的弹出是这样的
var dfd=$.Deferred();
dfd.progress(function(data){
alert(data);
}).done(function(data){
alert("done:>>>>>"+data);
}).fail(function(data){
alert("fail:>>>>"+data);
});
function getProcess(){
dfd.notify("我是progress回调函数的参数");
var a=true;
//下面判断是为了执行done还是fail
if(a){
dfd.resolve("执行done.....");
}else{
dfd.reject("执行fail......");
}
}
<input type="button" value="确定" onclick="getProcess()" />
根据以上分析,Deferred对象才有done这样的反法,
根据$.ajax().done()推测$.ajax()返回的应该是Deferred对象?
姑且认为这个结论是对的吧.
那么jQuey除了$.ajax()有done方法外,还有哪些东西有done方法.
$.when(d);d是一个或多个延迟对象,或者普通的JavaScript对象。
下面看一下参数是一个普通对象的.
现在说一说多个延迟的同一个调用
$.when($.ajax("1.json"), $.ajax("2.json"),$.ajax("3.json"))
.done(function(data1, data2,data3) {
console.log(data1);
console.log(data2);
console.log(data3);
}).fail(function(data1,data2,data3){
console.log(data1);
console.log(data2);
console.log(data3);
});
他把$.ajax()对象给返回回来了
这个地方的用的是ajax做的延迟,
那么我们能不能用setTimeout模拟延迟
function delay(){
setTimeout(function(){
alert("执行啦");
},2000);
}
$.when(delay())
.done(function(){
alert("done");
});
不对,这个地方首先执行的是done,2s后执行的才是setTimeout.
思考思考,想一想上面的参数.
这个地方最多只是将delay()当做参数传递给done回调函数的参数.因为不是一个Deferred类型的参数.
因为$.ajax()返回Deferred类型才能使用done一样.
那么要怎么样才能让delay返回一个Deferred对象来完成我们的延迟模拟呢.
现在让我们回想一下上面的第一串代码$.Deferred();
这个可以返回Deferred类型.
改写上面代码:
var dfd=$.Deferred();
function delay(dfd){
var bool=true;
setTimeout(function(){
alert("delay的setTimeout执行啦!");
if(bool){
dfd.resolve("done");
}else{
dfd.reject("fail");
} },2000);
return dfd;
} $.when(delay(dfd))
.done(function(value){
alert(value);
}).fail(function(value){
alert(value);
});
这个时候我们终于实现了延迟,回到功能.
上面说了 done只要一遇到resolve或fail遇到reject就会立即执行,
那么我们在底部添加一行代码:
修改上面的代码:
var dfd=$.Deferred();
function delay(dfd){
var bool=true;
setTimeout(function(){
console.log("delay的setTimeout执行啦!");
if(bool){
dfd.resolve("done");
}else{
dfd.reject("fail");
} },2000);
return dfd;
} $.when(delay(dfd))
.done(function(value){
console.log("done1"+value);
}).fail(function(value){
console.log("fail1"+value);
});
dfd.resolve("我是来捣乱的....");
顺序变成了这样:
很明显破坏了我们模拟延迟的目的.
如何解决
将dfd从全局改成局部变量,这样别人就不能轻易的改变状态了.
function delay(){
var dfd=$.Deferred();
var bool=true;
setTimeout(function(){
alert("delay的setTimeout执行啦!");
if(bool){
dfd.resolve("done");
}else{
dfd.reject("fail");
}
},2000);
return dfd;
}
$.when(delay())
.done(function(value){
alert("done1"+value);
}).fail(function(value){
alert("fail1"+value);
});
还是那句话:done只要一遇到resolve或fail遇到reject就会立即执行
改写上面的代码:
function delay(){
var dfd=$.Deferred();
var bool=true;
setTimeout(function(){
console.log("delay的setTimeout执行啦!");
if(bool){
dfd.resolve("done");
}else{
dfd.reject("fail");
}
},2000);
return dfd;
}
var delay2=delay();
delay2.resolve();
$.when(delay())
.done(function(value){
console.log("done1"+value);
}).fail(function(value){
console.log("fail1"+value);
});
这个时候执行变成这样,2s后:
如果我们的Deferred可以这样任意的被篡改,那么我们的程序健壮何在,
有没有一个办法让外人无法访问到Deferred对象,但是又不影响我们的回调函数的调用.
答案是有:promise();
改写代码:
function delay(){
var dfd=$.Deferred();
var bool=true;
setTimeout(function(){
console.log("delay的setTimeout执行啦!");
if(bool){
dfd.resolve("done");
}else{
dfd.reject("fail");
}
},2000);
return dfd.promise();
}
//var delay2=delay();
//delay2.resolve();
$.when(delay())
.done(function(value){
console.log("done1"+value);
}).fail(function(value){
console.log("fail1"+value);
});
这个时候你在把注释放开,就会报错了.
在看下面这串代码的报错:
$.ajax().resolve();
是不是很熟悉的报错.
所以我们的$.ajax()更确切的说最终返回的是Promise对象.
$.ajax(),$.when()说白了不过是一个方法而已.
既然jQuery能够搞个$.ajax(),$.when()接口出来,我们理所当然的也能搞一个
这样的接口出来了.
回到最上面的那串代码:
$.Deferred(fn);
我们一直都是在用无参的$.Deferred();
那这个fn参数是干嘛的呢?fn主要用来部署异步或延迟操作的.
$.delay=$.Deferred(function(dfd){
setTimeout(function(){
alert("setTimeout执行啦!!!!");
dfd.resolve();
},2000);
});
$.delay.done(function(){
alert("done1");
});
注意:这里的dfd不需要我们调用时传递,自己会传一个Deferred对象进去
这样看上去是不是就和$.ajax()和$.when()差不多了.
但是又不太一样,$.ajax()和$.when()可以传参数我们的$.delay不能传递参数,他也不是一个方法,就是一个Promise对象.
继续优化上面的代码,使之可以传递参数:
$.delay = function(time) {
return $.Deferred(function(dfd) {
setTimeout(function() {
alert("setTimeout执行啦!!!!");
dfd.resolve();
}, time);
})
}
$.delay(5000).done(function() {
alert("done1");
});
代码优化好了之后,功能实现了;
此时问题又来了.$.delay()是jQuery已经定义过的一个方法,我们定义的方法额jQuery重名了
不如我们吧$.delay()改成一个普通的方法,不更好.
var delay = function(time) {
return $.Deferred(function(dfd) {
setTimeout(function() {
alert("setTimeout执行啦!!!!");
dfd.resolve();
}, time);
})
}
delay(5000).done(function() {
alert("done1");
});
或者是这样:
function delay(time) {
return $.Deferred(function(dfd) {
setTimeout(function() {
alert("setTimeout执行啦!!!!");
dfd.resolve();
}, time);
})
}
delay(5000).done(function() {
alert("done1");
});
上面说的是通过返回Promise对象使其有了done等接口,
能否直接在给出的函数上布置接口呢?这里就用到了我们之前用到的promise()
代码如下:
var dfd=$.Deferred();
function delay(d,time) {
setTimeout(function(){
alert("setTimeout执行啦!!");
d.resolve();
},time);
}
dfd.promise(delay);
delay.done(function() {
alert("done1");
});
delay(dfd,5000);
这里又出现了dfd这样的全局变量,而且在调用时还是需要传递dfd参数,似乎有点不好看,优化一下:
function ansy(time) {
var dfd = $.Deferred();
function delay(d, time) {
setTimeout(function() {
alert("setTimeout执行啦!!");
d.resolve("我被done弹出来了");
}, time);
}
dfd.promise(delay);
delay(dfd,time);
return delay;
} ansy(2000).done(function(value){
alert("done说:"+value);
});
转自:http://www.cnblogs.com/guoyansi19900907/p/5000267.html
随机推荐
- centos中crontab(计时器)用法详解
关于crontab: crontab命令常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行.该 ...
- Redis集群(一):基本概念
一.使用版本:3.0.0.0 二.基本概念: 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了. 异步复制(虽然是异步复制,但是执行写命令和复制命令到从节点几乎是 ...
- 100197C
合并果子 每一次取最小的两个合并 答案加上这两个值 因为这是一颗二叉树,我们计算一条路的长度,可以看成从叶子节点逐渐合并,直到根 #include<iostream> #include&l ...
- ios 图片点击两次禁止保存或拷贝
通常当你在手机或者pad上长按图像 img ,会弹出选项 存储图像 或者 拷贝图像,如果你不想让用户这么操作,那么你可以通过以下方法来禁止: img { -webkit-touch-callo ...
- 【HDU 5744】Keep On Movin
找出奇数个的数有几个,就分几组. #include<cstdio> #include<cstring> #include<algorithm> #include&l ...
- R语言快速入门上手
导言: 较早之前就听说R是一门便捷的数据分析工具,但由于课程设计的原因,一直没有空出足够时间来进行学习.最近自从决定本科毕业出来找工作之后,渐渐开始接触大数据行业的技术,现在觉得是时候把R拿下 ...
- Extract Fasta Sequences Sub Sets by position
cut -d " " -f 1 sequences.fa | tr -s "\n" "\t"| sed -s 's/>/\n/g' & ...
- Leetcode 200. number of Islands
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...
- UOJ244 【UER #7】短路
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- PowerDesigner中Table视图同时显示Code和Name
如题,实现如下的效果: 解决方法: 1.Tools-Display Preference 然后选中Code移到最上面