今天讲一个jquery中的延时对象:$.Deferred,这个东西和es6的Promise很像,resolve表示解决,reject表示拒绝,今天看看这个东西如何玩的。

基本用法

我们先来看一个最简单$.Deferred用法,一个$.Deferred对象可以从内部resolve/reject或者外部resolve/reject:

内部实现

$.Deffered里面一共有三种状态:pending(处理中),resolved(解决),rejected(拒绝)。

内部维护了三个$.Callbacks队列( $.Callback相关知识),每个队列都对应一种状态,里面都放着相应需要处理的回调方法,分别通过progress,done,fail向队列里面添加方法。

换句话说,一个$.Deffered内部其实就是靠这三个$.Callback队列玩的,每个队列的add和fire都有特定的名字:

resolve队列的add叫done,fire叫resolve。

reject队列的add叫fail,fire叫reject。

progress队列的add叫progress,fire叫notify。

其中resolve队列和reject队列是一次性的,只能被fire一次, progress队列可以多次fire。

当我们定义一个$.Deffered的时候,resolve队列和reject队列就已经放入了一些默认的处理方法,代码如下:

图示如下:

background Layer 1 var d=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected Deferred对象 resolve reject notify

也就是说一开始定义的$.Deferred,resolve和reject队列就已经把“后事”准备好了,首先是改变当前的状态,变成resolved/rejected,其次就是制约另外一个队列(resolve队列制约reject队列,reject队列制约resolve队列),最后把progress队列给锁定。也就是说一旦调用了resolve()或者reject(),那么三个队列都废了,不能再用了。

我们来看一个有done,fail,progress的复杂一点的例子,他们就是分别把回调加在了resolve,reject,progress队列上:

background Layer 1 var d=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected Deferred对象 resolve reject notify d.done(f1).done(f2); f1 f3 d.fail(f3).fail(f4); d.progress(f5).progress(f6); f2 f4 f5 f6

always

always其实很简单,就是在每个done后fail后面都加入这个方法,这样无论成功还是失败都会调用这个方法。

background Layer 1 var d=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected Deferred对象 resolve reject notify d.always(f1); f1 f1

promise

一个延迟对象的promise提供一个不能操作状态的对象,也就是说promise返回的对象不能resolve/reject/notify,但是可以done/fail/progress:

假如promise里面传了对象,那么是将$.Deferred的不操作状态的方法合并到对象上。使得这个对象后面可以继续挂载回调方法。

then

这个方法比较复杂一点,它最多接受三个参数,分别放在resolve,reject,progress的队列后面:

background Layer 1 var d=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected Deferred对象 resolve reject notify d.then(f1,f2,f3) f1 f2 f3

then返回非Deferred对象

then比较特殊,如果then的后面再接了回调,那么参数为then的返回值:

因为then返回的是一个新的Deferred对象,因此也有自己完整的三个队列,多个then连在一起,就像一个炮竹一样,一个串一个。由主Deferred引爆,然后到then1的Deferred对象,再到then2的Deferred对象。。。

background Layer 1 var d=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify d.then(f1).done(f2); f1 f1=function(){return 'aaa';} d d.resolve(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify f2 d.then 如果then返回的是Deferred对象,那么then后面的回调将由返回的Deferred对象触发 调用 参数为'aaa' 如果then返回的是不是Deferred对象,那么在原Deferred对象完成后, 将同步触发then对应的动作。

我们来看一个有多个then的复杂情况:

background Layer 1 var d=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify d.then(f1).done(f2).then(f3).done(f4); f1 f1=function(){return 'aaa';} d d.resolve(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify f2 d第一个then 调用 参数为'aaa' f3=function(){return 'bbb';} resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify f4 d第二个then f3 调用 参数为'bbb'

大家可以感受一下then的挂载规律,then里面的方法是挂在上一个Deferred对象上的,then后面的方法是挂在then队列里的,待会看源码的时候就会发现这个规律。

then返回Deferred对象

如果then的返回值为Deferred对象的话,那么只有这个Deferred状态改变才能执行then后面的方法:

相当于说这个时候的then和新的Deferred关联了,引爆老的Deferred对象无法使then引爆,必须引爆新的Deferred对象才能使then里面的队列执行。

background Layer 1 var d=$.Deferred(),d1=$.Deferred(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify d.then(f1).done(f2); f1 f1=function(){return d1;} d resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify d1 d.resolve(); d1.resolve(); resolve队列 reject队列 progress队列 state=resolved reject队列disable progress队列lock resolve队列disable progress队列lock state=rejected resolve reject notify f2 d.then 调用 如果then返回的是Deferred对象,那么then后面的回调将由返回的Deferred对象触发

实现的代码也是比较绕,代码内部同时包含新Deferred,旧Deferred,以及返回的结果:

then其实是在老的Deferred的resolve,reject,progress队列上都放了一个方法,同时自己也返回了一个新的Deferred对象,拥有自己的队列。

then以后所加入done,fail,progress什么的都是then自己的队列上。

根据then里面的返回值,决定then挂载的方法是由老的Deferred引爆还是由新的Deferred引爆。

其他文章

0
我要评论

评论

返回
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

提交
还可以输入500个字