deferred对象

       最近做项目,调用后端接口,需要等到2个ajax返回再执行另一个ajax,首先想到的是使用promise,但是考虑到浏览器的兼容和编译问题,只能放弃。最后使用了标志位来解决这个问题,在调用之前设置一个flag,返回结果后改变这个flag值,一层层的判断。虽然方法笨,但解决了问题,项目结束后,看到了$.when().done().then(),觉得这是一个比较好的解决方法。

       介绍$.when().done().then()之前,先说一个deferred对象,这个是jquery1.5.0引入的新功能。deferred翻译过来就是延迟,所以deferred对象的作用就是“延迟”到某个时间点执行,可以用来解决jquery的回调函数。

一、jquery1.5.0版本以后,$.ajax()返回的是deferred对象,可以进行链式操作。如下所示:

$.ajax("test.html")

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

可以看出,.done()相当于success方法,.fail相当于error方法。

二、可以为同一个操作指定多个回调函数

在上个栗子中,如果还想再执行一个回调函数怎么办?

简单,直接在后面接着

.done(function () {console.log(1);})

可以随心所欲添加多个回调函数,按照添加顺序执行回调函数。

三、多个操作指定同一个回调函数

重头戏来了,也就是我开篇说到的,等到2个ajax的结果,再执行回调,这个时候就可以用到$.when()了。

$.when($.ajax('test1.html'), $.ajax('test2.html'))

.done(function () {console.log('成功了');})

.fail(function () {console.log('失败了');})

回调函数会等两个ajax都执行完后才执行,如果都成功会执行done里的回调,如果有一个失败或者都失败,执行fail里的回调。

四、任何操作都可以使用deferred对象的方法,指定回调函数

deferred对象最大的优点就是,把这套回调函数接口,从ajax操作扩展到了所有操作,无论是同步还是异步操作。如下,一个等待很久的wait操作:

var wait = function () {

    var tasks = function(){

        console.log('执行完毕');

    }

    setTimeout(tasks, 5000);

}

指定回调函数

$.when(wait())

.done(function () {console.log('成功了');})

.fail(function () {console.log('失败了')})

运行程序,你会发现,直接执行了done函数,这是为什么呢?

原因在于,$.when()的参数必须是一个deferred对象,现在对wait()进行改写。

var dtd = $.Deferred();//新建一个deferred对象

var wait = function () {

    var tasks = function () {

        console.log('执行完毕');

        dtd.resolve();//改变deferred对象的执行状态

    }

    setTimeout(tasks, 5000);

    return dtd;

}

现在wait已经是一个deferred对象了,可以使用上面的回调函数方法,wait执行完后,执行done函数。

五、deferred.resolve()和deferred.reject()

deferred对象有三个执行状态:未完成,已完成,已失败。若是已完成,则调用done函数;若是已失败,则调用fail函数;若是未完成,则一直等待,或者指定progress()方法指定回调函数(jq1.7添加)。ajax操作,deferred对象会根据返回结果,自动改变状态,但wait操作不会,需要我们手动改变。resolve方法就是把状态从未完成变成已完成,而reject就是从未完成变成已失败

六、deferred.promise()

在第四条中,我们创建了一个deferred对象,把这个赋给了一个全局变量,这样存在一个隐患,我可以在外部改变状态,例如:

var dtd = $.Deferred();//新建一个deferred对象

var wait = function () {

    var tasks = function () {

        console.log('执行完毕');

        dtd.resolve();//改变deferred对象的执行状态

    }

    setTimeout(tasks, 5000);

    return dtd;

}

$.when(wait())

.done(function () {console.log('成功了');})

.fail(function () {console.log('失败了')})

dtd.resolve();

如上所示,这时done函数会立即执行,没有达到我们想要的效果。所以jq提供了deferred.promise()方法,即deferred对象又返回了另外一个deferred对象。这个新的deferred对象只开放与改变执行状态无关的方法(done或fail方法),不开放改变执行状态的方法(resolve或reject方法)。改变一下上面的代码:

var wait = function (dtd) {

    var dtd = $.Deferred();//内部新建一个deferred对象

    var tasks = function () {

        console.log('执行完毕');

        dtd.resolve();//改变deferred对象的执行状态

    }

    setTimeout(tasks, 5000);

    return dtd.promise();//返回promise对象

}

$.when(wait())

.done(function () {console.log('成功了');})

.fail(function () {console.log('失败了')})

dtd.resolve();//此时,这个语句说无效的

如上,可以把deferred对象变成一个局部变量

七、$.Deferred(函数名)

除了上面说的在内部新建deferred对象,还有一种方法,就是使用deferred对象的建构函数$.Deferred(),直接把函数名作为参数传入,$.Deferred()生成的对象默认作为这个函数的参数。即:

$.Deferred(wait)

.done(function () {console.log('成功');})

.fail(function () {console.log('失败')})

八、在wait对象上部署Deferred接口

除上述两种方法,还有一种就是在wait对象上直接部署Deferred接口,如下

var dtd =$.Deferred();//生成deferred对象

var wait = function (dtd) {

    var tasks = function () {

        console.log('执行完毕');

        dtd.resolve();

    }

    setTimeout(tasks, 5000);

}

dtd.promise(wait);//在wait对象上部署Deferred接口

wait.done(function () {console.log('成功')})

.fail(function () {console.log('失败')})

wait(dtd);

用以上这种方法,wait可以直接调用done(),fail()。

九、总结

1.$.Deferred();生成一个deferred对象

2.deferred.done();指定成功时的回调操作

3.deferred.fail();指定失败时的回调操作

4.deferred.resolve();手动改变执行状态从未完成到已完成,从而触发done()方法

5.deferred.reject();手动改变执行状态从未完成到已失败,从而触发fail()方法

6.deferred.promise();无参数时,返回一个新的deferred对象,该对象的执行状态无法手动改变;有参数时,作用为在参数上部署Deferred接口

7.$.when();为多个操作指定同一个回调函数

8.deferred.then(success, fail);接收两个参数,第一个参数为成功时的回调操作,第二个参数为失败时的回调操作,相当于done(),fail()的综合写法。第二个参数可以省略,只有一个参数时,默认为成功时的回调操作

9.deferred.always();无论成功还是失败,最后都会执行的操作

10.deferred.state();确认deferred对象的当前状态

11.deferred.isResolved();确认deferred对象是否已被解决

12.deferred.isRejected();确认deferred对象是否已被拒绝,即已失败

13.deferred.catch();deferred对象失败时,调用添加的操作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容