Deferred 对象
Deferred 对象,是 jQuery 的一个特别的对象,用来解决回调函数的问题。
1.5 开始,$.ajax 方法也开始使用这个对象。1.5- 时,$.ajax() 方法返回的是 XHR 对象。之后 1.5+ 开始,返回的是一个 Deferred 对象。因此,原先设置在对象中的 success 和 error 属性方法不再使用,取而代之的是一些回调方法,包括 done 和 fail。而且调用方式是通过链式调用来实现,如:
对某个操作指定多个回调函数
如上面的 ajax 的栗子,在 ajax 操作结束后有绑定了两个回调函数。但其实,可以连续绑定多个回调函数的,直接在后面继续调用即可。
为多个操作指定相同的回调函数
这是 deferred 对象的一个特点,也是其优点。它允许我们为多个事件指定共同的回调函数。
在下面这个栗子中,用到的是 $.when() 方法:
Deferred 使用
deferred 对象使用的范围不仅仅只是 ajax(),其他普通操作也适用。不管是 ajax 操作还是本地操作,也不管是异步操作还是同步操作,都可以通过使用 deferred 对象来指定回调函数。
那么,怎么给具体操作指定回调函数呢?这就利用了 deferred 对象的状态值。
deferred 对象的状态值有:pending、resolved(已完成)、rejected(已失败)。
状态值通过使用 deferred 对象的属性方法——resolve()、reject() 来改变状态值。
在上面的栗子中,dfd.resolve() 是必须的,不然的话会 done() 会立即执行。
但是有个问题,假如 dfd.resolve() 是在外部执行的话,done() 方法就会在 foo 操作完成之前就执行,这样就没有了回调函数的意义。
因此,就需要对这种情况进行预防。
防止执行状态被外部改变的几种方案
deferred.promise()
promise() 方法的作用是在原来对象的基础上,返回一个另一个 deferred 对象。这个对象中,屏蔽了和改变执行状态值有关的方法(如 resolve() 和 reject() ),只开发和状态值无关的方法。这样使得状态被隐藏起来不能被改变。
(但是有个问题,上面栗子中,dfd 还是一个全局变量,那么可以跳过 d 对象直接操作 dfd,这样使用 promise 不是没有意义了?)
通过改良后,得到一个更好的方案:
这样,dfd 这原来的 deferred 对象就是个局部变量,外界不能访问,不会被改变状态值。而且,binding 返回的是 promise 后的对象,也不能改变状态值。
直接使用构造函数 $.Deferred()
自定义的操作不变,还是 binding,但是我们直接把它传入 $.Deferred()。
直接在操作的函数上部署 deferred 接口
|
其他属性方法
.state()
返回 deferred 对象的状态值
.always()
只要 deferred 对象状态变化,就会触发执行
.progress() & .notify()
progress() 可以让我们指定一个回调函数;
而 notify() 方法则是,当它被调用时,progress() 指定的回调函数就会被执行。
其用意是提供一个接口,使得在非同步操作执行过程中,可以执行某些操作,比如定期返回进度条的进度。
.then()
概述
then() 方法可以一次性设置多个回调函数。接受的参数有三个,分别是 resolved、rejected 的回调方法,以及 progress() 指定的回调函数。其中,后两者是可选。
返回值
值得注意的是,在 jQuery 1.8-,then() 和 .done().fail() 是等价的。在 1.8+,then() 返回一个新的 promise 对象。而 done() 返回的是原有的 deferred 对象。如果 then() 指定的回调函数有返回值的话,该返回值会作为参数,传入后面的回调函数
1.8- 的结果:
1.8+ 的结果:
利用 then() 的特点
既然 then() 指定的回调函数会修改返回值,那么,我们可以利用这个特性,在调用其他回调函数时,对之前操作返回的值进行处理。
(其余的坑等接触了 jQuery 源码的相关知识后再填)