jQuery.Deferred 对象
实例上的方法
一共14个
- deferred.resolve(args) / defered.resolveWith(context,args)
- deferred.reject(args) / deferred.rejectWith(contex,args)
- deferred.done()
- deferred.fail()
- deferred.always()
- deferred.notify() 当使用的时候,只要
deferred
对象的状态没有改变为resolved
或rejected
,可以访问通过deferred.then
和deferred.progress
添加的函数。否则,不起作用。 - deferred.notifyWith(context, ['args])
- deferred.progress() 添加回掉函数列,属于
notify
一列。当deferred
对象是resolved
或者rejected
,无法添加。 - deferred.promise() // 返回的对象是
deferred
子集,只能添加,不能改变状态。 - deferred.state() // 返回状态字符串,
pending
,resolve
,reject
- deferred.catch()
- deferred.then()
注意点
- resolve 之后,无论是 done 还是 then 方法添加函数,都会自动执行,并且,参数都是 resolve 参数
- 但是,resolve 之后,done/then 的链式操作上的 done/then 是不能收到 resovle 参数的,收到的是上一个的返回值
其他相关方法
-
$.when(deferreds)
传入延迟对象(通常表示异步事件),返回Promise 对象(延迟对象的一个子集)。然后调用其他的方法
- 比如
setTimeout
是一个异步事件,需要改装成deferred
对象之后,传入
-
$elem.promise()
主要用在动画上
// setTimeout 与 deferred
function wait () {
var def = $.Deferred();
setTimeout(function () {
console.log('finished!');
def.resolve();
},2000)
return def;
}
// 使用 when 之后返回的是 promise 对象,不能改变状态,相对于`deferred`对象,更加安全
$.when(wait())
.done(function () {console.log("成功")})
.fail(function () {console.log("错误")})
Deferred 源码分析
框架
jQuery.extend({
Deferred: function (func) {
// 四个重要的变量
var tuples,
state = "pending",
promise = {},
deferred = {};
// 将 promise 对象整合到 deferred 对象上
promise.promise(deferred);
// 如果使用构造函数时,有参数`func`,就要使用`call`调用
if (func) {
func.call(deferred, deferred);
}
// 返回对象
return deferred;
}
})
初始化
var tuples = [
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
];
jQuery.each(tuples, function (i, tuple) {
var list = tuple[2],
stateString = tuple[5];
// 其实 `done`等方法实质上是回调对象的`add`方法
pormisep[tuple[1]] = list.add;
if (stateString) {
// 在函数列队中添加三个初始化函数
/*
1. 改变状态字符串
2. 使对立面的函数队列无效
3. 锁住`progress`函数队列
*/
list.add(function () {state = stateString;},tuples[3 - i][2].disable, tuples[0][2].lock);
}
// `resolve`等方法内部使用的是`cb.fireWith()`
deferred[tuple[0]] = function () {
deferred[tuple[0] + "With"](this === deferred ? undefined : this, arguments);
return this;
}
// `resolveWith`等方法内部使用的是`cb.fireWith()`
deferred[tuple[0] + "With"] = list.fireWith;
});
then方法
var promise = {
then: function ( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
// 返回的是新 deferred 对象的 promise 对象
// newDefer 就是这里新生成的 deferred 对象
return jQuery.Deferred(function (newDefer) {
jQuery.each(tuples, function (i, tuple) {
// action 就是 触发方法名
// fn 就是需要添加到不同序列的函数
var action = tuple[0],
fn = jQuery.isFunction(fns[i]) && fns[i];
// deferred 相应的序列上添加 这个匿名函数
deferred[tuple[1]](function () {
// 这里的 arguments 应该是 匿名函数的
// 记得 callbacks 中 memory, 匿名函数即使是没有参数,在 memory 的情况下是可能有的
var returned = fn && fn.apply(this, arguments);
// 判断返回值,返回值如果是 deferred 对象
if (returned && jQuery.isFunction(returned.promise)) {
// 如果返回的是 deferred 对象,链式操作,需要等到 返回的deferred对象改变
// 那么就将点燃的权利交给 returned 的序列中
returned.promise()
.done(newDefer.resolve)
.fail(newDefer.reject)
.progress(newDefer.notify);
} else {
// 如果返回值只是非 deferred 对象
// this 是 newDefer
newDefer[action + "With"](this === promise ? newDefer.promise() : this, fn ? [returned] : arguments);
}
});
});
fns = null;
}).promise();
},
promise: function (obj) {
return obj != null ? jQuery.extend(obj, promise) : promise;
}
}
Deferred 的 resolve 注意事项
- 当延迟对象被 resolved 时,任何通过
deferred.then
或deferred.done
添加的doneCallbacks
,都会被调用 - 回调函数的执行顺序和它们被添加的顺序是一样的
- 传递给 deferred.resolve() 的 args 参数,会传给每个回调函数
- 当延迟对象进入 resolved 状态后,再添加的任何 doneCallbacks,当它们被添加时,就会被立刻执行,并带上传入给
resolve
的参数 - 但是,resolve 之后,done/then 的链式操作上的 done/then 是不能收到 resovle 参数的
Deferred 中 promise 对象
- 其实
done
,fail
,progress
方法属于promise
对象 -
promise
对象,由属于deferred
对象,deferred
对象上有resolve
,reject
,notify
等方法 -
promise
对象上promise
方法,是将传入对象进行包裹,然后返回
网友评论