Jquery Deferred 详解

学会使用Deferred对象以及其相关函数, 可以优雅的解决开发过程中一些异步执行问题

----应用篇----

开发场景
你是否经历过这种代码场景:
function demo1(){
    .....

    const result = demo2();
    if(result){
        ....
    }else{
        ....
    }

    .....
}

function demo2(){
    const changeStatus = true; //一个可预期的返回值
    $.ajax({
        url: "xxx",
        async: true,
        .....
        .....
        success: function (reslut) {
            if(.....){
                changeStatus = false;
            }
        }
    });
    return changeStatus;
}

上述代码在执行时, 你会发现changeStatus会一直返回true

原因: ajax为非阻塞代码块, 在发送请求时不会阻塞当前线程的执行, 而请求是耗时动作, 必然会比代码执行速度慢, 所以在success方法执行之前, 方法已经返回changeStatus的值
解决办法:
  1. 把ajax设置成同步请求, async: false, 带来的问题: 如果请求耗时时间过长, 会造成页面假死的情况,

  2. 把后续逻辑都放到success中(抽取受到返回值影响的代码块, 放到success中)

function demo1(){

    .....

    demo2();

    .....

}

function demo2(){
    const changeStatus = true; //一个可预期的返回值
    $.ajax({
        url: "xxx",
        async: true,
        .....
        .....
        success: function (reslut) {
            if(.....){
                changeStatus = false;
            }
            //转移的代码, 此代码块受到changeStatus的状态影响
            if(changeStatus){
                ....
            }else{
                ....
            }
        }
    });
    return changeStatus;
}

此种做法, 增加了代码的维护成本, 也使代码可读性变差(丑)

那么可不可以用一种优雅的方式, 解决这个问题呢?

----Deferred篇----

名词解释

deferred: 延期的, 推迟

对象的功能说明
A Deferred object starts in the pending state. Any callbacks added to the object with 
 deferred.then(), deferred.always(), deferred.done(), or deferred.fail() are queued to 
be executed later. Calling deferred.resolve() or deferred.resolveWith() transitions the
Deferred into the resolved state and immediately executes any doneCallbacks that are set.
Calling deferred.reject() or deferred.rejectWith() transitions the Deferred into the rejected
state and immediately executes any failCallbacks that are set. Once the object has entered the 
resolved or rejected state, it stays in that state. Callbacks can still be added to the resolved 
or rejected Deferred — they will execute immediately.

简单翻译: deferred对象在初始化的时候是延迟状态的, 任何添加到队列里的回调方法会推迟执行, 调用resolve()或者 resolveWith()方法来转换当前实例进入到resolve状态, 并且执行对应状态的回调方法, 调用reject()或rejectWith()方法 来使实例进入reject状态, 并执行对应的回调方法, 一个对象实例当进入到不同的状态时, 它会保持状态, 回调方法会添加到当前 实例中, 并被立即执行

对象的方法说明

deferred.then(doneFilter, failFilter, progressFilter):

doneFilter
Type: Function()
当实例为resolve状态时被触发

failFilter
Type: Function()
当实例为rejected状态时被触发

progressFilter
Type: Function()
当实例状态改变时会被触发

deferred.always(alwaysCallbacks)

alwaysCallbacks
Type: Function()
实例状态改变时总会被触发, 参数为function或function数组

deferred.done(doneCallbacks)

doneCallbacks
Type: Function()
实例状态为resolve时会被触发, 参数为function或function数组

deferred.fail(failCallbacks)

failCallbacks
Type: Function()
实例状态为 rejected时会被触发, 参数为function或function数组
应用场景

jquery提供两种方式返回deferred对象: $.ajax $.when

  1. $.ajax().then().fail()...
  2. $.when(...).done().fail()...

着重讲一下when, 这个方法在不传参的时候, 会返回一个resolve状态的promise(不可变状态的deferred对象)

when可接收多个deferred对象实例, 用来判断最终的状态, exp:

const d1 = $.Deferred();
const d2 = $.Deferred();

$.when( d1, d2 ).done(function ( v1, v2 ) {
    console.log( v1 ); // "Fish"
    console.log( v2 ); // "Pizza"
});
// 只有所有deferred对象为resolve状态, 回调函数done才会执行
d1.resolve( "Fish" );
d2.resolve( "Pizza" );

----代码改进篇----

通过以上学习, 我们可以知道, 使用deferred对象和when配合, 可以达到方法延期执行的效果

so, 改变原来的代码如下:


const ajaxDone = $.Deferred();

function demo1(){
    .....

    demo2();

    $.when(ajaxDone).done(function(result) {
         if(result){
             ....
         }else{
             ....
         }
    });

    .....
}


function demo2(){
    $.ajax({
        url: "xxx",
        async: true,
        .....
        .....
        success: function (reslut) {
            if(.....){
                ajaxDone.resolve(false);
            }
            ajaxDone.resolve(true);
        }
    });
}

关于Deferred的应用场景, 还有很多, 在开发过程中, 一定要灵活运用, 多思考, 花心思来打磨自己的代码, 才会使自己的技术能力得到提高

个人博客 点击前往

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jQuery 中的 Deferred 对象提供了一种优雅的方式来处理异步操作,它可以让我们更方便地控制异步操作的状态和执行顺序。下面是 Deferred 对象的常用方法: 1. $.Deferred():创建一个 Deferred 对象。 2. deferred.done():当 Deferred 对象的状态变为已完成时,调用该方法注册的回调函数。 3. deferred.fail():当 Deferred 对象的状态变为已失败时,调用该方法注册的回调函数。 4. deferred.always():无论 Deferred 对象的状态是已完成还是已失败,都调用该方法注册的回调函数。 5. deferred.then():当 Deferred 对象的状态变化时,调用该方法注册的回调函数。它可以接受两个参数,第一个参数是已完成状态的回调函数,第二个参数是已失败状态的回调函数。 6. deferred.promise():返回一个 Promise 对象,该对象可以被传递给其他函数或者方法,但只能调用 then()、catch() 和 finally() 方法,不能改变 Deferred 对象的状态。 下面是一个使用 Deferred 对象的示例代码: ```javascript function asyncAction() { var defer = $.Deferred(); setTimeout(function() { defer.resolve("Async Action Completed!"); }, 2000); return defer.promise(); } var promise = asyncAction(); promise.then(function(data) { console.log(data); }).fail(function() { console.log("Async Action Failed!"); }).always(function() { console.log("Async Action Done!"); }); ``` 在这个例子中,我们定义了一个 asyncAction() 函数,它返回一个 Deferred 对象。在该函数内部,我们使用 setTimeout() 函数模拟一个异步操作,并在两秒后调用 resolve() 方法,将 Deferred 对象的状态设置为已完成。然后我们使用 promise 变量保存该 Deferred 对象的 Promise 对象,并使用 then()、fail() 和 always() 方法注册回调函数。在 then() 方法中,输出异步操作完成的信息;在 fail() 方法中,输出异步操作失败的信息;在 always() 方法中,输出异步操作完成的信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值