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对象就是jQuery的回调函数解决方案。
对于耗时很长的操作(既可以是异步操作,也可以是同步操作),都可以使用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对象
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 ...})
...
$.when(func1(), func2())
.done(function() {...})
.fail(function() {...});
从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() {
//另一个回调函数
});
更多jQuery.Deferred对象的用法,可参考官方文档:http://api.jquery.com/jQuery.Deferred/