ES6原生提供的Promise对象已成为JavaScript实现异步编程的标准方式,而jQuery提供的Deferred对象,本质上是对Promise的进一步封装和增强。
以下为jQuery对Deferred的官方说明:
As of jQuery 1.5, the Deferred object provides a way to register multiple callbacks into self-managed callback queues, invoke callback queues as appropriate, and relay the success or failure state of any synchronous or asynchronous function.
另外,jQuery也提供了一个Promise对象,但该对象本质是在原来的Deferred对象上返回另一个Deferred对象,后者只开放与改变执行状态无关的方法,屏蔽与改变执行状态有关的方法,从而使得执行状态不能被改变。
This object provides a subset of the methods of the Deferred object (then, done, fail, always, pipe, progress, state and promise) to prevent users from changing the state of the Deferred.
Deferred对象的基本使用
简单说,Deferred对象就是jQuery的回调函数解决方案。
对于耗时很长的操作(既可以是异步操作,也可以是同步操作),都可以使用Deferred对象来进行异步编程。
. D e f e r r e d ( ) 和 .Deferred()和 .Deferred()和.when()的基本用法,$.when()方法的参数只能是Deferred对象
//新建Deferred对象
var def = $.Deferred();
//需要使用回调函数进行监听的操作,并传入和返回deferred对象
var func = function(def) {
//do something
...
//改变Deferred状态
def.resolve();
...
//返回Deferred对象
return def;
};
//使用when()监听Deferred状态变化
$.when(func())
.done(function() {...}) //成功时执行,即状态为resolved
.fail(function() {...}) //失败时执行,即状态为rejected
.always(function() {...}); //已完成执行,无论是何种状态
Deferred.promise()的基本用法,避免Deferred对象状态被外部改变
//新建Deferred对象
var def = $.Deferred();
//需要使用回调函数进行监听的操作
var func = function(def) {
//do something
...
//改变Deferred状态
def.resolve();
...
//返回promise对象
return def.promise();
};
//改为对返回的Promise()对象进行操作
var d = func(def);
$.when(d)
.done(function() {...}) //成功时执行,即状态为resolved
.fail(function() {...}) //失败时执行,即状态为rejected
.always(function() {...}); //已完成执行,无论是何种状态
//外部改变Deferred状态,但此种情况下是无效的
d.resolve();
由此可见,jQuery提供的Promise对象可以看做是Deferred对象的特例,与ES6原生提供的Promise对象所具有的意义并不相同。
为了避免Deferred状态被外部改变,更好的做法是把新建Deferred对象的语句放到操作函数内部,即避免把Deferred作为一个全局对象。
为同一个操作指定多个回调函数,它们按照添加顺序执行。
$.when(func())
.done(function() {//do something ...})
.done(function() {//do otherthing ...})
...
为多个操作指定同一个回调函数,如果都成功了,就执行done()指定的回调函数,只要有一个失败了,就执行fail()指定的回调函数。
$.when(func1(), func2())
.done(function() {...})
.fail(function() {...});
Deferred对象在Ajax中的运用
从jQuery 1.5开始,$.ajax()返回的便不再是XMLHttpRequest对象,而是Deferred对象,因此可以进行链式操作,并支持执行多个回调。甚至可以在请求完成后,仍然可以注册回调函数。
另外,在Ajax操作中,Deferred会根据返回对象,自动改变自身的执行状态。
//1.5版本之前的写法
$.ajax({
url: '...',
success: function() {...},
error: function() {...},
complete: function() {}
});
//1.5版本之后的写法
var def = $.ajax(...)
.done(function() {...})
.fail(function() {...})
.always(function() {...});
def.always(function() {
//另一个回调函数
});
Deferred对象常用方法总结
- $.Deferred() 生成一个deferred对象;
- $.when() 为若干个操作指定回调函数
- deferred.done() 指定操作成功时的回调函数
- deferred.fail() 指定操作失败时的回调函数
- deferred.then() 成功done()和失败fail()的合并写法
- deferred.always() 完成时的回调函数,无论状态如何总是执行
- deferred.progress() 指定在deferred生成进度通知时的回调函数
- deferred.resolve() 改变deferred状态为“已完成”,从而触发done()方法
- deferred.reject() 改变deferred状态为“已失败”,从而触发fail()方法
- deferred.promise() 没有参数时,返回一个Promise对象;有参数时,作用为在参数对象上部署deferred接口。
更多jQuery.Deferred对象的用法,可参考官方文档:http://api.jquery.com/jQuery.Deferred/