前端多层回调问题解决方案之$.Deferred

javascript引擎是单线程的,但是通过异步回调可以实现IO操作并行执行能力,当业务逻辑复杂的时候我们就进入回调地狱。

本文讲得ajax是在jquery1.5以前的版本,目的旨在让我们理解延迟对象的应用场景,jquery1.5之后,ajax默认就是延迟对象,可以进行链式操作

举例:

a(funtion(){
    b(funtion(){
        c(funtion(){
            d(funtion(){
                e(funtion(){
                    f(funtion(){
                        g(funtion(){
                            finish();
                        });
                    });
                });
            });
        });
    });
});      

这还是比较简单的操作,如果每个回调函数还有N多操作,那么更加头疼了。

解决方法:通过jQuery的when().done()实现

1. 函数a,b,c,d,e,f,g都这样写

function a(){
    var dtd = $.Deferred();

    //这里延迟操作,可能是ajax,也可能是setTimeout
    $.post(url,{},function(data){
        ....
        alert("执行完毕!");
      dtd.resolve(); // 改变Deferred对象的执行状态
    }) ;

    return dtd.promise();
}

2. 使用

$.when(
    a(),
    b(),
    c(),
    d(),
    e(),
    f(),
    g()
).done(finish).fail() ;

PS: 除了$.when().done()组合,还有一种组合$.when().then()。

done是在when中的延迟对象dtd都resolve的时候才回执行done中的操作,then是延迟对象有一个resolve就执行。类似于“与”和“或”。

如上的例子,如果a函数里面的ajax请求返回的不是我们想要的结果,我们不想让done执行,应该怎么做呢?

function a(){
    var dtd = $.Deferred();

    //这里延迟操作,可能是ajax,也可能是setTimeout
    $.post(url,{},function(data){
        if(data == 1){
            dtd.resolve(); // 改变Deferred对象的执行状态
        }else{
            dtd.reject(); // 作用和resolve正好相反
        }      
    });

    return dtd.promise();
}

如果a函数服务器返回的是1, 那么done可以执行,如果不是1,那么不会执行done,而是立即执行fail。

如果这里是then那么不会受到影响,只要a,b,c,d,e,f,g有一个resolve。

还有一个函数$when().always(),这个不管when中resolve还是reject,最后都会执行always。

文章转自: http://www.myjscode.com/page/article10.html

原文地址:https://www.cnblogs.com/lvmylife/p/7466668.html