jquery中的promise

本文的主要内容有:
* 以前的ajax写法
+ 原生ajax
+ jquery的ajax
+ 多个ajax顺序请求时:嵌套,异步回调
* 引入promise后的ajax
* 其他地方使用promise

1. 以前的ajax

1.1 原生的ajax写法

以前我们写ajax请求时,如果是用原生的JavaScript代码写呢,通常是这样的一种形式:

var XHR = (function(){
    var obj = null; // xhr对象
    function init(){
        create();
        send();
    }
    // 创建xhr对象
    function create(){
        if(window.XMLHttpRequest){
            obj = new XMLHttpRequest();
        }else if(window.ActiveObject) {
            obj = new ActiveObject('Microsoft.XMLHTTP');
        }
        echange();
    }
    // 发送消息
    function send(){
        var v = parseInt(Math.random()*100);
        obj.open("get", "test.php?v="+v, true);
        obj.send(null);
        obj.onreadystatechange =echange;
    }
    // 接收消息
    function echange(){
        /*
        0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
        1 (初始化) 对象已建立,尚未调用send方法
        2 (发送数据) send方法已调用,但是当前的状态及http头未知
        3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
        4 (完成) 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据
        */ 
        if(obj.readyState==4 && obj.status==200){
            var result = JSON.parse(obj.responseText);
            console.log(result);
        }
    }
    return {
        init:init
    }
})();
1.2 jquery的ajax写法

原生的ajax代码能比较清晰的看出ajax的流程,可是如果每次都写这么多的代码就会造成很多的不便。不过在jquery中,已经对ajax的代码进行封装,使用jquery的ajax时就不用写这么多的代码了。当然,我们自己也可以对原生的ajax代码进行封装。

$.ajax({
    url : 'test.php', // 请求地址
    data : {'v':v},   // 发送的数据
    dataType : 'json',// 返回的数据格式
    type : 'get',     // 请求的方式:get|post

    // 发送前执行
    beforeSend : function(){
        console.log("beforeSend");
    },
    // 返回成功执行
    success : function(result){
        console.log(result);
    },
    // 返回失败执行
    error : function(err){
        console.log(err);
    },
    // 无论成功还是失败都会执行
    complete : function(){
        console.log('complete');
    },
    // 状态码对应的操作
    statusCode : {
        200 : function(){
            console.log("200, ok");
        },
        404 : function(){
            console.log("404, page not found");
        }
    }
})

上面的代码中虽然列了很多的选项,但是不是所有的都能用到的,可以结合实际的例子进行相应的取舍。比如beforeSend, statusCode等,如果实在是用不到,也可以不写的。

1.3 多个ajax顺序请求时

在使用这样的ajax进行多次顺序请求时,我们会采用嵌套的方式来进行。

// 首次ajax请求
$.ajax({
    url:'test.php',
    success:function(){
        // 请求完成后进行下次的请求
        $.ajax({
            url:'test1.php',
            success:function(){
                // 进行下次的ajax请求
                $.ajax({
                    url:'test.php',
                    success:function(){
                        // ...
                    }
                })
            }
        })
    }
})

如果有比较多的ajax请求时,我们发现这样的代码实在是不利于我们的阅读,而且造成以后代码的修改和维护很困难。那有没有一种写法,我们既能分开写ajax请求,又能顺序执行。

当然有啦,一个比较简单的方式就是使用异步回调的方式:

// 第一个ajax请求
function ajax(callback){
    $.ajax({
        url:'test.php',
        success:function(){
            callback();
        }
    })
}
// 第二个ajax请求
function ajax1(callback){
    $.ajax({
        url:'test.php',
        success:function(){
            callback();
        }
    })
}

// 将第二个ajax方法作为第一个方法的回调方法
// 如果有多个ajax请求时,可以调用多个回调方法
ajax(ajax1); // ajax(ajax1(ajax2));  

2. 现在的ajax

Promise/Deferred模式在JavaScript框架中最早出现于Dojo的代码中,被广为所知则来自于jQuery 1.5版本,该版本几乎重写了ajax部分,使得调用ajax时可以通过如下的形式进行:

$.ajax({ url:'test.php' })
    .success(function(){ })
    .error(function(){ })
    .complete(function(){ })

这使得即使不调用success(), error()等方法,ajax也会执行,这样的调用方式比预先传入的回调让人觉得舒适一些。在原始的API中,一个事件只能处理一个回调,而通过Deferred对象,可以对事件加入任意的业务处理逻辑,示例代码如下:

$.ajax({ url:'test.php' })
    .success(function(){ })
    .error(function(){ })
    .success(function(){ })

Promise/Deferred模式在2009年时被Kris Zyp抽象为一个提议草案,发布在CommonJS规范中,随着使用Promise/Deferred模式的应用逐渐增多,CommonJS草案目前已经抽象出了Promise/A、 Promise/B、Promise/D这样典型的异步Promise/Deferred模型,这使得异步操作可以以一种优雅的方式出现。

jQuery的1.5版本之后,$.ajax()返回的就是promise对象,而且其他的jQuery对象也能通过调用promise()返回一个promise对象。因此,上面的ajax可以写成这样:

var promise = $.ajax({url:'test.php'});
promise.success(function(){
    // success
})
promise.error(function(){
    // error
})

不过在1.8版本之后,jquery已经不推荐success(),error()和complete()方法了,推荐使用done(), fail()和always(),分别对应着前面三个方法。修改如下:

var promise = $.ajax({url:'test.php'});
promise.done(function(){
    // done
})
promise.fail(function(){
    // fail
})
promise.always(function(){
    // always
})

我们也可以用then()方法把done()和fail()合并到一起。

promise.then(function(){
    // done
}, function(){
    // fail
})

第一个参数表示done方法,第二个方法表示fail方法;如果只传递一个参数的话,就表示done方法。

同时在jquery中还提供了$.when()方法

$.when(deferreds ) : 提供一种方法来执行一个或多个对象的回调函数, Deferred(延迟)对象通常表示异步事件

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

$.when( $.ajax({url:'test.php'}) ).then(function(data, status, jqXHR){
    // done
    // console.log(data, status, jqXHR);
})

在案例中有多个延迟对象传递给jQuery.when ,该方法返回一个新的“宿主”延迟对象,跟踪所有已通过Deferreds聚集状态。 当所有的延迟对象被受理(resolve)时,该方法才会受理它的 master 延迟对象。当其中有一个延迟对象被拒绝(rejected)时,该方法就会拒绝它的 master 延迟对象。如果 master 延迟对象被受理(resolved),那么会传入所有延迟对象的受理(resolved)值,这些延迟对象指的就是传给 jQuery.when 的参数。例如,当延迟对象是 jQuery.ajax() 请求,那么传入的受理(resolved)参数就是请求用的 jqXHR 对象,传入顺序就是它们在参数列表中的顺序。

在多延迟情况下,如果延迟一被拒绝,jQuery.when触发立即调用 master 延迟对象的 failCallbacks。请注意,在上述情况中,有一些延迟对象依然是不能被受理(unresolved)的。那么,在这种情况下,如果需要执行一些额外的处理,例如,取消所有未完成的 ajax 请求,你可以在闭包中进行保持 jqXHR 对象的引用,并且在 failCallback 中检查或取消它们。

$.when(
    $.ajax({url:'test.php'}),
    $.ajax({url:'test1.php'})
).done(function(result, result1){
    console.log(result);
    console.log(result1);
}).fail(function(err){
    console.log("error");
})

当两个ajax都执行成功时就会调用done方法,否则只要其中一个失败就会执行fail方法。

promise对象下可调用的方法有:
!image

3. promise对象使用的其他场景

promise对象不只是能在ajax中使用,在其他有时间延迟的地方也能够使用,比如animate(), fadeIn(), fadeOut() 等,我们想在fadeIn()之后执行animate(),然后执行fadeOut让他隐藏。

一种方法就是使用这个方法提供的回调函数,来确保它的先后顺序:

<style type="text/css">
    .process{background: #ccc; display: none; width: 150px; height: 150px;}
</style>
<body>
    <div class="process"></div>
</body>
<script>
    // 记得加载jquery库
    $('.process').fadeIn(function(){
        $(this).animate({'width':'300px', 'height':'300px'}, 1000, function(){
            $(this).fadeOut();
        })
    })
</script>

还有就是用上面讲到的promise对象。

$('.process').fadeIn().promise()
    .then(function(){ 
        $(this).animate({'width':'300px', 'height':'300px'}, 1000)
    }).then(function(){
        $(this).fadeOut();
    });
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值