jquery Deferred对象的好处 (一)
1、引子
先看一个普通的业务逻辑请求
$.ajax({
url:'test.htm',
data:{
userId:'001',
param1:"a1",
param2:'a2'
...
},
succsss:function(){
...
}
});
这是一段普通的请求代码,里面携带了userId以及其他的一些业务参数。userId是用来识别用户身份的,几乎每个业务请求都要带上它。
现在为考虑到安全性将userId存在于服务器的session中(用户登录时生成),下次请求是浏览器只需cookies中的信息带过去就行了,而无需带上userId。
传统的网站session过期时往往要用户去重新登录,而现在产品经理改了需求,业务请求身份过期时不跳登录,而是激活身份,正常完成业务请求。
好!easy啦。。无非是再多发一个激活身份的请求(先叫他refreshUrl),上代码
//以ajax请求同步的方式实现
var tokenResult=true;//代表身份是否过期的变量
function tokenRefresh(){
var result=false;
$.ajax({
url:refreshUrl,
ansy:false,
data:{
param1:"a1",
param2:'a2'
...
},
succsss:function(){
if(sussess){
//刷新session
result=true;
return;
}
else {
//error catch
}
//doSomethings..
}
});
return result;
}
function doSomethings(){
$.ajax({
url:'test.htm',
ansy:false,
data:{
param1:"a1",
param2:'a2'
...
},
succsss:function(){
if(errorCode===-1){
//身份过期
tokenResult=false;
return;
}
//doSomethings..
}
});
}
doSomethings();
if(!tokenResult&&tokenRefresh()){
//session过期时刷新session,再发一次请求
doSomethings();
}
代码量是大了点但是勉强是可以使用的而且安全性也可以保证。过几天产品经理又来改需求了(又改需求。。),他说有时候发用户反馈业务请求时会出现几秒钟的空白时间,需要价格等待界面。说加就加,代码就这样写
//其他的不变无非就加个等待页面的显示和隐藏
showWaitUI();//发起请求时显示等待页面,上面放个会转的菊花.gif
function doSomethings(){
$.ajax({
url:'test.htm',
ansy:false,
data:{
param1:"a1",
param2:'a2'
...
},
succsss:function(){
if(errorCode===-1){
//身份过期
tokenResult=false;
return;
}
else if(success){
//doSomethings...
hideWaitUI();//隐藏等待框
//执行正常的业务逻辑
}
}
});
}
doSomethings();
if(!tokenResult&&tokenRefresh()){
//session过期时刷新session,再发一次请求
doSomethings();
}
现在问题来了,当你运行调试时发现等待页面是出来了但是小菊花转不动了,一查发现是ajax同步请求阻塞了UI线程,那还有什么办法只好使用异步呗。
//修改代码
function tokenRefresh(doSthFun){
$.ajax({
url:refreshUrl,
ansy:false,
data:{
param1:"a1",
param2:'a2'
...
},
succsss:function(){
if(sussess){
//刷新session,继续执行业务操作
doSthFun()
}
else {
//error catch
}
//doSomethings..
}
});
}
function doSomethings(){
$.ajax({
url:'test.htm',
ansy:false,
data:{
param1:"a1",
param2:'a2'
...
},
succsss:function(){
if(errorCode===-1){
//身份过期
tokenRefresh(doSomethings);
return;
}
else if(success){
//doSomethings...
hideWaitUI();//隐藏等待界面
//执行正常的业务逻辑
}
}
});
}
showWaitUI();//显示等待界面
doSomethings();//执行业务操作
但是段代码嵌套调用逻辑性和可读性都很差,而且不安全,很容易发生死锁,从而陷入回调地狱,因此这里引出Deferred对象解决上述问题。
2、Deferred 对象的介绍
简单说,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是”延迟”,所以deferred对象的含义就是”延迟”到未来某个点再执行。
它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口。
在高于1.5版本的jquery库中ajax请求返回的都是一个deferred对象,因此ajax请求的回调可以写成链式的形式
$.ajax({
url:'text.html'
}).done(function(data){
//doSthings With success...
}).fail(function(error){
//doSthings With fail...
});
done()相当于success方法,fail()相当于error方法。采用链式写法以后,代码的可读性大大提高。
deferred对象的最大优点,就是它把这一套回调函数接口,从ajax操作扩展到了所有操作。也就是说,任何一个操作不管是ajax操作还是本地操作,也不管是异步操作还是同步操作都可以使用deferred对象的各种方法,指定回调函数。
//for example...
//定义一个很耗时的操作函数
var doSomethings=function(){
var tasks = function(){
if(succsee){
alert('success');
}else{
alert('fail');
}
}
setTimeOut(tasks,50000);
}
如果我们将它作为指定函数,可以用$.when()实现。由于$.when()只支持deferred对象。因此需要改写上述代码为。
var doSomethings=function(){
// 新建一个deferred对象
var deferred= $.Deferred();
var tasks = function(){
if(succsee){
alert('success');
//设置执行状态为已完成,执行done回调
deferred.resolve(data);
}else{
//设置执行状态为失败,执行fail回调
deferred.reject(data);
alert('fail');
}
}
setTimeOut(tasks,50000);
//调用deferred对象的promise方法,让执行状态不能再外部被改变
return deferred.promise();
}
$when(doSomethings()).done(function(data){
//dosomething with success...
}).fail(function(){
//dosomething with fail...
})
3、使用
根据deferred的知识,原来的业务操作请求代码可以改写成如下形式:
var deferred=$.Deferred(); // 新建一个Deferred对象
function doSomethings(){
$.ajax({
url:'test.htm',
ansy:false,
data:{
param1:"a1",
param2:'a2'
...
},
succsss:function(data){
if(errorCode===-1){
//身份过期
deffered.resolve(false);
return;
}
else if(success){
//doSomethings...
hideWaitUI();//隐藏等待界面
//执行正常的业务逻辑
}
deffered.resolve(true);
},
error:function(){
deferred.reject();
}
});
return deferred.promise();
}
showWatiUI();//显示等待界面
$.when(doSomethings())
.done(fuction(tokenResult){
if(!tokenResult){
tokenRefresh();
doSomethings();
}
}).always(function(){
//无论成功失败读执行
hideWaitUI();
});
那么问题也解决了,再次运行程序,会发现菊花已经可以转动了。
注:(如果想对deferred对象有更多的了解,请阅读阮一峰老师的《jQuery的deferred对象详解》)
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html