美文网首页
deferred对象学习(下)(持续更新...)

deferred对象学习(下)(持续更新...)

作者: 小碗碗碗碗 | 来源:发表于2020-04-20 19:19 被阅读0次

    前言:在上一次的deferred对象学习中,对于then的用法并没有展开讨论,同时上一篇文章中说到“$.when()的参数只能是deferred对象”这一说法有误。
    特此在本篇文章中更正when用法,同时对then用法展开讨论。

    一、Promise对象与Deferred对象的区别

    Promise对象是ES6的异步操作解决方案,为异步操作提供统一接口。它起到代理作用,充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口,可以让异步操作写起来,就像在写同步操作的流程。
    Promise的用法:
    根据ES6的规定,Promise对象是一个构造函数,可以生成Promise实例,构造函数接受一个回调函数,该回调函数的参数有两个,resolve和reject,均由JS引擎提供,不用自己部署;生成实例后,可以用then方法分别指定resolved和rejected状态的回调函数。

    function asyncFunc() {
        return new Promise(function(resolve, reject) {
            // some async task
            if (/*异步操作成功*/) {
                resolve(value);
            } else {
                reject(err);
            }
        });
    }
    
    asyncFunc().then(function(value) {
        //do something
    }).catch(function(err) {
        //do something
    });
    

    Deferred对象是jQuery用来统一处理回调函数的一个解决方案,在1.5.0版本开始引入。jQuery中的Deferred对象实现了Promise,并且将resolve和reject方法暴露在了构造函数外面,使得改变promise对象的状态更为灵活。
    deferred.promise()是返回了一个纯粹的promise对象,即不能在外部调用resolve和reject方法。
    Deferred的用法:
    jQuery的所有Ajax操作函数,默认返回的就是一个deferred对象

    var dfd = $.Deferred();
    dfd.then(function(value) {
        //do something
    }).catch(function(err) {
        //do something
    });
    

    二、promise.then()与deferred.then()的区别

    promise.then()
    then()返回一个新的promise对象,如果then()指定的回调函数有返回值,该返回值会作为参数,传入后面的回调函数。
    deferred.then()
    在jQuery 1.8之前,then()只是.done().fail()写法的语法糖,两种写法是等价的。
    在jQuery 1.8之后,then()返回一个新的deferred对象,而done()返回的是原有的deferred对象。如果then()指定的回调函数有返回值,该返回值会作为参数,传入后面的回调函数。

    (注:由于Deferred对象实现了Promise,为了便于描述,后面直接统称为Promise对象)

    .catch()与then()的rejected回调作用几乎一致。但是由于Promise的抛错具有冒泡性质,能够不断传递,这样就能够在下一个catch()中统一处理这些错误。同时catch()也能够捕获then()中抛出的错误,所以建议不要使用then()的rejected回调,而是统一使用catch()来处理错误
    当状态已经改变为resolved后,即使抛出错误,也不会触发then()的错误回调或者catch()方法。
    then() 和 catch() 都会返回一个新的Promise对象,可以链式调用。

    三、使用then()解决回调地狱

    首先,看下Promise实例的异步方法中传参promise和then()中返回promise有什么区别

    // p1异步方法中返回p2
    let p1 = new Promise ( (resolve, reject) => {
        resolve(p2)
    } )
    let p2 = new Promise ( ... )
    p1.then(
        //todo
        alert('complete1');
    ).then(
        //todo
        alert('complete2');
    )
    
    // then()中返回promise
    let p1 = new Promise ( (resolve, reject) => {
        resolve()
    } )
    let p2 = new Promise ( ... )
    p1.then(
        alert('complete1');
        () => return p2
    ).then(
        //todo
        alert('complete2');
    )
    

    p1异步方法中传参p2
    p1的状态取决于p2,如果p2为pending,p1将等待p2状态的改变,p2的状态一旦改变,p1将会立即执行自己对应的回调,即第一个then()中的方法。
    由于then()本身就会返回一个新的promise,所以第二个then()中的方法针对的是第一个then()本身返回的promise。
    if p2 resolved --> p1 resolved --> complete1

    then()中返回promise
    如果在第一个then()中的方法手动返回p4,那么第二个then()中的方法针对的是p4,这样就可以在p4中再次通过 resolve() 和 reject() 来改变状态,第二个then()中的方法将等待p4状态的改变。
    p1 resolved --> complete1 --> if p2 resolved --> complete2

    由此可见,当then中的方法返回的是Promise对象时,会针对返回的Promise对象继续进行等待。这样可以更好地解决前端中的回调地狱问题(即回调嵌套)
    举例:A B C D 这4个返回Promise对象的方法,想要按顺序进行异步操作,即A执行完了再执行B,B执行完了再执行C…,则:
    A.then(B).then(C).then(D)

    四、$.when()的用法

    如果向 $.when 传入一个延迟对象,那么会返回它的 Promise 对象,可以继续绑定 Promise 对象的其它方法,例如 defered.then。
    当延迟对象已经被受理resolved或被拒绝rejected(通常是由创建延迟对象的最初代码执行的),那么就会调用适当的回调函数。
    例如,由 jQuery.ajax 返回的 jqXHR 对象是一个延迟对象,可以向下面这样使用:

    $.when( $.ajax("test.aspx") ).then(function(data, textStatus, jqXHR){
         alert( jqXHR.status ); // alerts 200
    });
    

    如果向 $.when 传入一个非延迟对象,那么它会被当作是一个被受理resolved的延迟对象,并且添加到上面的任何 doneCallbacks 都会被立刻执行,向 doneCallbacks 中传入的是原始的参数。
    在这种情况下,设定的任何 failCallbacks 永远都不会被执行,因为延迟对象永远不会被拒绝rejected。例如:

    $.when( { testing: 123 } ).done(
        function(x) { alert(x.testing); } /* alerts "123" */
    );
    

    相关文章

      网友评论

          本文标题:deferred对象学习(下)(持续更新...)

          本文链接:https://www.haomeiwen.com/subject/awcdihtx.html