前言:

什么叫做递延对象,生成一个递延对象只需调用jQuery.Deferred函数,deferred这个单词译为延期,推迟,即延迟的意思,那么在jQuery中

又是如何表达延迟的呢,从递延对象中的then方法或许能找到这种延迟的行为,本文重点解读递延对象中的then方法

jQuery回调、递延对象总结篇索引:

jQuery回调、递延对象总结(上篇)—— jQuery.Callbacks

jQuery回调、递延对象总结(中篇) —— 神奇的then方法

jQuery回调、递延对象总结(下篇) —— 解密jQuery.when方法

设计思路:

在递延对象构造中,分别有三组回调对象,每一组回调对象都有与之对应的行为(action,add listener),和状态(final state),

这些行为都归纳为递延对象中的(触发回调,添加函数到回调列表中等)方法

jQuery.Deferred构造源码

Deferred构造源码除了then函数源码外,其他都非常简单,这里不做过多解读,后面将重点讨论then方法

jQuery.extend({

    Deferred: function( func ) {
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
state = "pending",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
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[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
});
fns = null;
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {}; // Keep pipe for back-compat
promise.pipe = promise.then; // Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add
promise[ tuple[1] ] = list.add; // Handle state
if ( stateString ) {
list.add(function() {
// state = [ resolved | rejected ]
state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock
// 可以看看上篇中lock方法的各种场景调用
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
} // deferred[ resolve | reject | notify ]
deferred[ tuple[0] ] = function() {
// 如果方法不被借用,那么回调中的this对象为promise,没有触发回调的方法
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
deferred[ tuple[0] + "With" ] = list.fireWith;
}); // Make the deferred a promise
promise.promise( deferred ); // Call given func if any
// 作用于then方法
if ( func ) {
func.call( deferred, deferred );
} // All done!
return deferred;
}
});

神奇的then方法

在实际项目应用中,一个页面或许有多个ajax请求,你可能会这样做:

$.ajax({ url1, ... });
$.ajax({ url2, ... });
$.ajax({ url3, ... });
...

这样做的缺点:

1、多个ajax同时发送请求,可能会造成服务器压力,对于富应用页面来说,如果请求过多,那是必然的;

2、对于页面底部,或者说首屏不展示给用户浏览的部分需要发送的ajax请求,没有必要让它一开始加载页面后就发送请求,这样会造成页面响应缓慢

jQuery递延对象中的then方法好像天生就是为了解决以上问题而设计的,它可以按照顺序依次处理多个异步请求,即第一个请求处理完后,

再处理第二个请求,以此类推,这样既可以减轻服务器压力,又可以先发送首屏(从上到下)页面部分的请求,使页面响应更快

来看看一段非常优雅的实例代码

var promiseA = $.get(urlA);
promiseA.always(doneFnA, failFnA, progressFnA); var promiseB = promiseA.then(function(){
return $.get(urlB);
});
promiseB.always(doneFnB, failFnB, progressFnB);

或者你也可以这样写,但并不建议:

var promiseB = $.get(urlA).then(function(){
var state = this.state();
// 针对第一个ajax请求的处理
switch (state) {
case 'resolved' :
doneFnA();
break;
case 'rejected' :
failFnA();
break;
case 'pending' :
progressA();
break;
default:
break;
}
return $.get(urlB);
});
promiseB.always(doneFnB, failFnB, progressB);

上面代码是如何运行的呢:

首先发送第一个ajax请求,当promiseA对象执行过resolve(或reject、notify)后,即:第一个请求成功或失败后,将依次执行回调doneFnA

(或failFnA、progressFnA),then中的匿名函数(注意代码的顺序,之前代码顺序有误,把promiseA.always放在了then方法执行之后,现已改过来了),

匿名函数中发送第二个ajax请求,当请求成功或失败后,将执行对应的回调函数(doneFnB或failFnB、progressFnB)

衍生后的代码

var promiseA = $.get(urlA);
// 这里添加promiseA的回调 var promiseB = promiseA.then(function(){
return $.get(urlB);
});
// 这里添加promiseB的回调 var promiseC = promiseB.then(function(){
return $.get(urlC);
});
// 这里添加promiseC的回调 var promiseD = promiseC.then(function(){
return $.get(urlD);
});
// 这里添加promiseD的回调

再来看看then函数中的构造源码,通过上面的实例分析,相信眼前的你会恍然大悟的

promise = {
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
// 返回后的promise对象与newDefer对应
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
// 为第一个递延对象添加回调
deferred[ tuple[1] ](function() {
var returned = fn && fn.apply( this, arguments ); // 如果回调返回的是一个递延对象,newDefer将根据这个返回的递延对象的状态来触发行为
if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
}
// 如果回调返回的不是一个递延对象,newDefer将根据第一个(deferred)递延对象的状态来触发行为
else {
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
});
fns = null;
}).promise();
}
}

PS: 如有描述错误,请帮忙指正,如果你们有不明白的地方也可以发邮件给我,

  如需转载,请附上本文地址及出处:博客园华子yjh,谢谢!

jQuery回调、递延对象总结(中篇) —— 神奇的then方法的更多相关文章

  1. jQuery回调、递延对象总结(下篇) —— 解密jQuery.when方法

    前言: 前一篇文章中重点总结了一下then方法,它主要用来处理多个异步任务按顺序执行,即前一个任务处理完了,再继续下一个,以此类推: 而这一章节jQuery.when方法也是处理多个异步任务,它把多个 ...

  2. jQuery回调、递延对象总结(上篇)—— jQuery.Callbacks

    前言: 作为参数传递给另一个函数执行的函数我们称为回调函数,那么该回调又是否是异步的呢,何谓异步,如:作为事件处理器,或作为参数传递给 (setTimeout,setInterval)这样的异步函数, ...

  3. jQuery回调、递延对象总结

    jQuery回调.递延对象总结(上篇)—— jQuery.Callbacks jQuery回调.递延对象总结(中篇) —— 神奇的then方法 jQuery回调.递延对象总结(下篇) —— 解密jQu ...

  4. jQuery回调、递延对象总结(一)jQuery.Callbacks详解

    前言: 作为参数传递给另一个函数执行的函数我们称为回调函数,那么该回调又是否是异步的呢,何谓异步,如:作为事件处理器,或作为参数传递给 (setTimeout,setInterval)这样的异步函数, ...

  5. jQuery的deferred对象详解 jquery回调函数

    http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html jQuery的 ...

  6. jQuery的deferred对象学习

    #copy { background-color: lightgreen; padding: 15px; margin: 10px } 一.deferred对象简介 deferred对象是jquery ...

  7. jQuery中异步操作对象Deferred

    以下介绍一下jQuery中Deferred对象的使用: 1. 通过$.Deferred生成一个deferredObj对象; 2. deferredObj.done()指定操作成功时的回调函数; 3. ...

  8. 【转载】学习资料存档:jQuery的deferred对象详解

    我在以前的文章里提到promise和deferred,这两个东西其实是对回调函数的一种写法,javascript的难点之一是回调函数,但是我们要写出优秀的javascript代码又不得不灵活运用回调函 ...

  9. jQuery的deferred对象使用详解——实现ajax线性请求数据

    最近遇到一个ajax请求数据的问题 ,就是想要请求3个不同的接口,然后请求完毕后对数据进行操作,主要问题就是不知道这3个请求誰先返回来,或者是在进行操作的时候不能保证数据都已经回来,首先想到能完成的就 ...

随机推荐

  1. hdfs创建级联文件夹

    一个文件夹 hdfs dfs -mkdir /out /一定要有 级联 hdfs dfs -mkdir -p /out/ags 需要家-p

  2. JSR303注解

    Annotation 属于Bean Validation 规范 应用位置 作用 对Hibernate Core中的元数据的影响 @AssertFalse yes field/property 检查被标 ...

  3. 关于AWR报告命中率指标的解释(转)

    文章转自:http://blog.itpub.net/24558279/viewspace-762371/ 从Oracle 10g开始,Oracle给广大DBA提供了一个性能优化的利器,那便是Auto ...

  4. Android成长日记-Android四大组件之Service组件的学习

    1.什么是Service? Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它 ...

  5. Myeclipse的show in breadcrumb

    m如何取消eclipse的show in breadcrumb 不小心点了show in breadcrumb,在编辑器界面上面多一层路径条,多余碍事,不晓得怎么取消,搞了半天终于弄好,方法如下: 点 ...

  6. ExceptionLess异常日志收集框架-1

    哈哈,中秋和代码更配哦,不知不觉一年过半了,祝园友们中秋快乐 前一阵子在博客园看到了一篇博文 http://www.cnblogs.com/savorboard/p/exceptionless.htm ...

  7. Linux部分命令使用记录(实时更新)

    1. 实时监控文件内容变化 tail -f xxx 2. 查看文件前5行 head -5 xxx 3. ssh对话失效后关闭对话(可以避免直接关闭终端) ~. (好像显示有问题,按钮是 -.) 4. ...

  8. 【Alpha版本】 第七天 11.15

    一.站立式会议照片: 二.项目燃尽图: 三.项目进展: 成 员 昨天完成任务 今天完成任务 明天要做任务 问题困难 心得体会 胡泽善 完成我要招聘的招聘详情显示,完成简历填写及显示功能 完成我要应聘的 ...

  9. excel2013添加坐标轴名称label

    图画好了,x.y轴没有名称,怎么办那 点击左上角有个---添加图标元素----里面有轴标题应该就是

  10. Nginx个人简单理解

    首先我们来补充下一些基本知识: 什么是代理服务器? 先举个简单的例子,现在我们在百度访问谷歌的网站,发现现在进不去,这个时候我们可以FQ(关于FQ,可以借鉴下这个博文:http://zhangge.n ...