jQuery教程之then详解(4)
沉沙 2018-11-16 来源 : 阅读 1003 评论 0

摘要:本篇教程介绍了jQuery教程之then详解(4),希望阅读本篇文章以后大家有所收获,帮助大家对jQuery的理解更加深入。

本篇教程介绍了jQuery教程之then详解(4),希望阅读本篇文章以后大家有所收获,帮助大家对jQuery的理解更加深入。

<

传统的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表示立马执行回调,
所以这个地方的弹出是这样的

黄金搭档 progress(fn)和notify(value)

progress和done之类的方法截然不同.
progress(fn)的fn表示一个回调函数,这个回调函数由notify()方法通知执行.
代码:
复制代码
复制代码

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({address:"china",sex:"男"})
.done(function(data){
    console.log(data.address)
});

这个例子主要是为了演示参数的传递的
前面说了同一延迟的多个回调的两种写法
看下面:

1.

$.ajax("1.json")
.done(function(data){
    alert("done1")
}).done(function(){
    alert("done2");
});

2.

$.ajax("1.json")
.done(function(data){
    alert("done1")
},function(){
    alert("done2");
});

结合when用法

$.when($.ajax("1.json"))
.done(function(data){
    console.log(data);
});

现在说一说多个延迟的同一个调用
复制代码
复制代码

$.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);
});

复制代码
复制代码

好了总算说完了.
现在我们看看jQuery1.7.2的ajax源码:

为了阅读方便,我把源码删掉了一部分,行号和真实的jquery行号对不上.
ajax最终返回的是jqXHR,而在7424行在bei部署成了Promise对象.
因此一开始的疑惑终于解决了,$.ajax()返回的是Promise,并非我们在官网上看到的是XMLHttpRequest对象.    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标WEB前端jQuery频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程