您的位置:首页 > Web前端 > JQuery

jquery中的promise

2015-04-18 14:02 483 查看
本文的主要内容有:

* 以前的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();
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: