在使用jQuery时,一个非常重要的功能就是ajax。但是jQuery的ajax一个很常用的方式会让代码可读性很差,那就是嵌套ajax使用。
比如这样的代码

$.ajax({
        url:"http://localhost:8080/jsonp",
        dataType:"jsonp",
        jsonpCallback:"callback",
        success:function (response) {
            console.log(1 + ":" + response);
            $.ajax({
                url:"http://localhost:8080/jsonp",
                dataType:"jsonp",
                jsonpCallback:"callback",
                success:function (response) {
                    console.log(2 + ":" + response);
                    $.ajax({
                        url:"http://localhost:8080/jsonp",
                        dataType:"jsonp",
                        jsonpCallback:"callback",
                        success:function (response) {
                            console.log(3 + ":" + response);
                        }
                    })
                }
            })
        }
    });

这个ajax请求被嵌套了两次次,主要原因就是因为在下一次的ajax请求的数据依赖于上一次ajax的数据(实例中并没有体现)。因此就在回调中又调用了两次。

function ajaxDemo(success){
        return $.ajax({
            url: "http://localhost:8080/jsonp",
            dataType: "jsonp",
            jsonpCallback: "callback",
            success: success
        })
    }

ajaxDemo(function (response) {
        console.log(1 + ":" + response);
        ajaxDemo(function (response) {
            console.log(2 + ":" + response);
            ajaxDemo(function (response) {
                console.log(3 + ":" + response);
            })
        })
    });

使用这样的方式可以稍微让代码优雅一点,但是嵌套在代码中仍然解决可能无穷无尽的嵌套代码块。于是jQuery就有引入了一种新的编程方式,使用promise进行ajax请求。比如这样:

function ajaxDemo(){
      return $.ajax({
          url: "http://localhost:8080/jsonp",
          dataType: "jsonp",
          jsonpCallback: "callback",
      })
}
ajaxDemo().then((response) => {
        console.log(1 + ":" + response);
        return ajaxDemo()
}).then((response) => {
        console.log(2 + ":" + response);
        return ajaxDemo()
}).then((response) => {
        console.log(3 + ":" + response);
});

这样的代码是不是看起来清爽了很多,对于每一次依赖于上一次的ajax调用的请求,只需要将其写成一个链式的调用而不是使用嵌套回调函数来实现具有数据依赖的多个ajax调用。其中promise保证了只有当前的ajax的回调函数执行完成之后才会进行下一次的ajax请求。

那么jQuery是如何实现这种调用接口方式的呢?其实就依赖于promise的机制,promise有很多中实现,jQurey也单独实现了自己的promise,而其中一个最关键的对象就是 Deferred 对象。
Defeffed对象的作用,顾名思义就是延迟地执行一个任务。

def = $.Deferred()
pro = {}
def.promise(pro)
pro.done(function(){console.log(123)})
deff.resolve()

def就是一个Deferred对象,而pro则是一个被def转化的promise对象,在对pro使用了promise函数,def就会增加几个方法:done, then, fail等函数。
done/then/fail函数会被添加到promise对象中,但是并不一定会被马上执行。如果pro对象已经执行过resolve()函数,那么这些任务在被添加之后就会马上触发。而如果resolve函数没有被调用,那么这些任务就会等待resolve调用而全部触发。
在jQuery的实现中

 deferred.promise( jqXHR );

jQuery将jqXHR请求对象转换成了一个promise对象,然后将complete,success,error等回调传入到promise对象中

// Install callbacks on deferreds
completeDeferred.add( splete );
jqXHR.done( s.success );
jqXHR.fail( s.error );

随后在jq的执行流程中,当有结果显示完成或者失败之后,就会去触发成功或者失败的回调函数

// Success/Error
if ( isSuccess ) {
          deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
 } else {
          deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
 }

同时,在jquery的ajax函数调用之后,返回的就是一个Deferred对象,于是链式地使用ajax就可以成立。

更多推荐

jQuery使用promise处理ajax