学习jQuery.Deferred

它用来解决JS中的异步编程,它遵循 Common Promise/A 规范。实现此规范的还有 when.js 和 dojo

 

$.Deferred作为新特性首次出现在版本1.5中,这个版本利用Deferred又完全重写了Ajax模块。

$.Deferred在jQuery代码自身四处被使用,分别是promise方法、DOM readyAjax模块、动画模块。

这里以版本1.8.3分析,由于1.7$.Callbacks从Deferred中抽离出去了,目前版本的deferred.js代码不过150行,而真正$.Deferred的实现只有100行左右。

 

$.extend标示符$上挂了两个方法,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
jQuery.extend({
     Deferred:  function ( func ) {
         var  tuples = [
                 // action, add listener, listener list, final state
                 "resolve" "done" , jQuery.Callbacks( "once memory" ),  "resolved"  ],
                 "reject" "fail" , jQuery.Callbacks( "once memory" ),  "rejected"  ],
                 "notify" "progress" , jQuery.Callbacks( "memory" ) ]
             ],
         ...
 
         // All done!
         return  deferred;
     },
     // Deferred helper
     when:  function ( subordinate  /* , ..., subordinateN */  ) {
         var  i = 0,
             resolveValues = core_slice.call( arguments ),
             length = resolveValues.length,
             ....
 
         return  deferred.promise();
     }
});

 

$.Deferred的实现

  1. 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态
  2. 创建了一个promise对象,具有state、always、then、primise方法
  3. 通过扩展primise对象生成最终的Deferred对象,返回该对象

 

$.when的实现

  1. 接受若干个对象,参数仅一个且非Deferred对象将立即执行回调函数
  2. Deferred对象和非Deferred对象混杂时,对于非Deferred对象remaining减1
  3. Deferred对象总数 = 内部构建的Deferred对象 + 所传参数中包含的Deferred对象
  4. 所传参数中所有Deferred对象每当resolve时remaining减1,直到为0时(所有都resolve)执行回调

 

这就是$.Deferred和$.when的全部了,各个方法及使用稍后介绍。

代码阅读中会发现then和when方法的实现最难理解,看多次,后感回味无穷,非常巧妙。then内部会用到不同寻常的递归,when用到了计数,每次异步成功后减一,直到为0后表示全部异步操作成功,这时才可执行回调。

 

上面提到Deferred里有3个$.Callbacks的实例,Deferred自身则围绕这三个对象进行更高层次的抽象。以下是Deferred对象的核心方法

 

下面举一些示例看看如何使用Deferred对象。

 

一、done/resolve

1
2
3
4
5
6
7
8
function  cb() {
     alert( 'success' )
}
var  deferred = $.Deferred()
deferred.done(cb)
setTimeout( function () {
     deferred.resolve()
}, 3000)

在HTTP中表示后台返回成功状态(如200)时使用,即请求成功后可执行成功回调函数。

 

二、fail/reject

1
2
3
4
5
6
7
8
function  cb() {
     alert( 'fail' )
}
var  deferred = $.Deferred()
deferred.fail(cb)
setTimeout( function () {
     deferred.reject()
}, 3000)

在HTTP中表示后台返回非成功状态时使用,即请求失败后可执行失败回调函数。

 

三、progress/notify

1
2
3
4
5
6
7
8
function  cb() {
     alert( 'progress' )
}
var  deferred = $.Deferred()
deferred.progress(cb)
setInterval( function () {
     deferred.notify()
}, 2000)

在HTTP中表示请求过程中使用,即请求过程中不断执行回调函数。这可用在文件上传时的loading百分比或进度条。

 

四、链式操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function  fn1() {
     alert( 'success' )
}
function  fn2() {
     alert( 'fail' )
}
function  fn3() {
     alert( 'progress' )
}
var  deferred = $.Deferred()
deferred.done(fn1).fail(fn2).progress(fn3)  // 链式操作
setTimeout( function () {
     deferred.resolve()
     //deferred.reject()
     //deferred.notify()
}, 3000)

这样可以很方便了添加成功,失败,进度回调函数。

 

五,便利函数then,一次添加成功,失败,进度回调函数

1
2
3
4
5
6
7
8
9
10
11
function  fn1() {
     alert( 'success' )
}
function  fn2() {
     alert( 'fail' )
}
function  fn3() {
     alert( 'progress' )
}
var  deferred = $.Deferred()
deferred.then(fn1, fn2, fn3)

调用then后还可以继续链式调用then添加多个不同回调函数,这个then也正是jQuery对 Common Promise/A 的实现。

 

六、使用always方法为成功,失败状态添加同一个回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
var  deferred = $.Deferred()
deferred.always( function () {
     var  state = deferred.state()
     if  ( state ===  'resolved' ) {
         alert( 'success' )
     else  if  (state ===  'rejected' ) {
         alert( 'fail' )
     }
})
setTimeout( function () {
     deferred.resolve()
     //deferred.reject()
}, 3000)

回调函数中可以使用deferred.state方法获取异步过程中的最终状态,这里我调用的是deferred.resolve,因此最后的状态是resolved,表示成功。

 

七、when方法保证多个异步操作全部成功后才回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function  fn1() {
     alert( 'done1' )
}
function  fn2() {
     alert( 'done2' )
}
function  fn3() {
     alert( 'all done' )
}
 
var  deferred1 = $.Deferred()
var  deferred2 = $.Deferred()
 
deferred1.done(fn1)
deferred2.done(fn2)
$.when(deferred1, deferred2).done(fn3)
 
setTimeout( function () {
     deferred1.resolve()
     deferred2.resolve()
}, 3000)

先后弹出了done1、done2、all done。 如果setTimeout中有一个reject了,fn3将不会被执行。

 

八、deferred.promise()方法返回只能添加回调的对象,这个对象与$.Deferred()返回的对象不同,只能done/fail/progress,不能resolve/reject/notify。即只能调用callbacks.add,没有callbacks.fire。它是正统Deferred对象的阉割版。

 

 

有了Deferred,我们使用jQuery书写ajax的风格可以这样了

1
2
3
$.ajax(url)
  .done(success)
  .fail(fail)

 

看似和以前比较也没什么优点,但它还可以添加多个回调

1
2
3
4
5
$.ajax(url)
  .done(success1)
  .done(success2)
  .fail(fail2)
  .fail(fail2)

1.5之前的则不行

 

如果多个请求完成后才算成功,1.5之前的是无法解决的,现在则可以用$.when搞定

1
2
3
var  ajax1 = $.ajax(url1)
var  ajax2 = $.ajax(url2)
$.when(ajax1, ajax2).done(success)

 

如果项目中有一些异步问题不妨用用Derferred。


转:http://www.cnblogs.com/snandy/category/285213.html

相关: http://www.cnblogs.com/littledu/articles/2813051.html
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值