在上一节中构建了deferred对象,实现了done/fail/process和resolve/reject/notify等方法,但是最重要的then,pipe管道接口我们还没有实现,我们考虑下:
var dfd = $.Deferred()
dfd.then(function(preVale) {
return 2 * preVale //4
}).then(function(preVale) {
return 3 * preVale //12
})
dfd.resolve(2)
then就是pipe,我们可以想象是一个管道,可以对回调模式使用瀑布模型。如案例所示,下一个回调都能取到上一个回调的值,这样一直可以叠加往后传递。
不难看出管道的风格就是链式的操作,每一个链上的结果都会反馈后下一个链,那么这个链式是不是传统的返回自身这个对象this呢?
常规的办法通过数组处理:右侧代码所示。
function aDeferred(){
//代码右侧代码
}
这样的结构当然是很简陋的,这里我们最终有一个本质的问题没有解决,jQuery中的then的返回还有可能是另一个新的异步模型对象,如ajax,因此还能实现done,fail,always,then等方法。所以采用简陋的数组的方式保存状态是很肤浅的了。
这时候jQuery采取了对象保存处理:
我们可以把每一次的then操作,当做是创建一个新的deferred对象,那么每一个对象都够保存自己的状态与各自的处理方法。通过一个办法把所有的对象操作都串联起来,这就是then或者pipe管道设计的核心思路了。
看jQuery的then结构:
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function(newDefer) {
jQuery.each(tuples, function(i, tuple) {
deferred[tuple[1]](function() {
// deferred[ done | fail | progress ]
});
});
}).promise()
其实在内部创建了一个新的Deferred对象,不过这里的不同是通过传递一个回调函数,参数是newDefer,其实Deferred内部就是为了改变下上下文this为deferred,然后传递deferred给这个回调函数了,所以newDefer就指向内部的deferred对象了。
那么对象之间如何关联?
jQuery.each(tuples, function(i, tuple) {
//取出参数
var fn = jQuery.isFunction(fns[i]) && fns[i];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
// 添加done fail progress的处理方法
// 针对延时对象直接做了处理
deferred[tuple[1]](function() {
var returned = fn && fn.apply(this, arguments);
if (returned && jQuery.isFunction(returned.promise)) {
returned.promise()
.done(newDefer.resolve)
.fail(newDefer.reject)
.progress(newDefer.notify);
} else {
newDefer[tuple[0] + "With"](this === promise ? newDefer.promise() : this, fn ? [returned] : arguments);
}
});
把then的方法通过:
deferred.done deferred.fail deferred.progress
加入到上一个对象的各自的执行队列中保存了。这样就实现了不同对象之间的关联调用。
同样如果then返回的是一个promise对象(ajax)的时候:
if (returned && jQuery.isFunction(returned.promise)) {
returned.promise()
.done(newDefer.resolve)
.fail(newDefer.reject)
.progress(newDefer.notify);
也可以直接处理了。
请验证,完成请求
由于请求次数过多,请先验证,完成再次请求
打开微信扫码自动绑定
绑定后可得到
使用 Ctrl+D 可将课程添加到书签
举报