deferred对象

2018-02-09  本文已影响0人  晴天小猪L

       最近做项目,调用后端接口,需要等到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对象失败时,调用添加的操作

上一篇 下一篇

猜你喜欢

热点阅读