前言:

前一篇文章中重点总结了一下then方法,它主要用来处理多个异步任务按顺序执行,即前一个任务处理完了,再继续下一个,以此类推;

而这一章节jQuery.when方法也是处理多个异步任务,它把多个异步任务(Promise对象)合并为一个Promise对象,这个合并后的Promise对象

到底是如何来更新它的状态,即何时执行,拒绝?让我们继续往下看吧!

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

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

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

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

设计思路(意图)

执行jQuery.when将会返回一个Promise对象,我们称作由when生成的Promise对象,如果给定的所有Promise对象均已执行,就立即执行

由when方法产生的Promise对象,如果给定的Promise对象中有任意一个被拒绝,就立即拒绝由when生成的Promise对象,这样做的意图

好像就是为了解决这样一种需求:在指定的多个异步事件都完成了,然后才能干自己想干的事情

源码解析

jQuery.extend({
// Deferred helper
// 参数为Promise对象,我们称作:给定的Promise对象
// when函数内部的deferred对象,我们称作:由when生成的Promise对象
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
// the count of uncompleted subordinates
// 用来存储给定的未执行(解决)的Promise对象的个数
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
// 我们称deferred为when生成的Promise对象
deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
// 如果给定的任意一个Promise对象未执行或拒绝,则通知由when生成的Promise对象为pending状态
// 注:contexts是由所有给定的Promise对象组成的数组,
// values是由处理所有给定的Promise对象的回调的参数组成的数组
if( values === progressValues ) {
deferred.notifyWith( contexts, values );
}
// 如果给定的Promise对象已执行(解决),且当未执行的Promise对象个数为0,
// 即:给定的所有Promise对象都已执行(解决),则立即执行由when生成的Promise对象
// 注:contexts是由所有给定的Promise对象组成的数组,
// values是由处理所有给定的Promise对象的回调的参数组成的数组(请看实例1)
else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
}, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length ); // resolveValues = core_slice.call( arguments ) // 别忘了最上面的这行代码
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
// 如果给定when的参数是一个Promise对象,则通知由when生成的Promise对象,通知什么,如何通知?
// 如果给定的Promise对象已执行,则执行由when生成的Promise对象(要等到所有给定Promise对象全部执行)
// 如果给定的任意一个Promise对象已拒绝,则拒绝由when生成的Promise对象
// 如果未执行或拒绝,默认是pending状态
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )
.progress( updateFunc( i, progressContexts, progressValues ) );
}
// 如果给定的不是一个Promise对象,那么负责减一
else {
--remaining;
}
}
} // if we're not waiting on anything, resolve the master
// 如果传递给when的参数都不是递延对象,则执行由when生成的Promise对象
if ( !remaining ) {
// resolveContexts为一个空数组new Array( length ),resolveValues是由when参数组成的一个数组
deferred.resolveWith( resolveContexts, resolveValues );
} return deferred.promise();
}
});

实例:关于执行由when生成的Promise对象的参数的问题

var promiseA = $.Deferred();
var promiseB = $.Deferred(); var doneFn = function(arg){
console.log(arg);
}; promiseA.done(doneFn);
promiseB.done(doneFn); promiseA.resolve('A'); // 'A'
promiseB.resolve('B'); // 'B' var whenFn = function(arg1, arg2){
console.log(this[0] === promiseA.promise()); // true
console.log(this[1] === promiseB.promise()); // true
console.log('promise' + arg1 + ', promise' + arg2 + ' All done!');
};
var whenPromise = jQuery.when(promiseA, promiseB);
whenPromise.done(whenFn); // true true 'promiseA, promiseB All done!'

jQuery回调、递延对象总结:

递延对象中的then方法作用于使多个异步任务按照顺序执行,而jQuery.when方法作用于在多个并发的异步任务执行完毕后再干自己感兴趣的事情;

jQuery递延对象是基于jQuery回调对象架构的,如果你想熟练掌握jQuery递延对象,请先移步jQuery.Callbacks对象

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

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

最新文章

  1. [MySQL性能优化系列]巧用索引
  2. CSS Reset / Normalize 如何进行样式重置
  3. 键盘ctrl+shift不能切换输入法
  4. c# 中的委托以及匿名方法lambda
  5. log4j的ConversionPattern参数的格式含义-转
  6. recurse_array_change_key_case()递规返回字符串键名全为小写或大写的数组
  7. ​? super T ? extends T
  8. C文件操作(转载)
  9. linux复制文件命令scp
  10. 数据库安全性操作——操作原则及SQL注入
  11. cpp(第八章)
  12. 虚拟硬盘格式vdi、vhd、vmdk相互转换
  13. 为 Debian 8 或 Debian 9(64 位)安装 .NET Core
  14. python控制台输出带颜色的文字方法
  15. Linux 安装软件之后设置PATH环境变量
  16. 使用Elasticsearch 出现的拒绝连接
  17. poj 2502 Subway【Dijkstra】
  18. EasyUI datebox 设置不可编辑后再次修改为可编辑失效的解决
  19. android 5.0安装应用冲突问题
  20. docker 安装vim

热门文章

  1. 【bzoj1922】 Sdoi2010—大陆争霸
  2. [Poi2000]公共串
  3. pythong中字符串strip的用法
  4. Gated Recurrent Unit (GRU)公式简介
  5. Git连接到自己的GitHub仓库
  6. uC/OS-II核心(Os_core)块
  7. 谁都能看懂的单点登录(SSO)实现方式(附源码)
  8. ListView 里面嵌套 GridView 遇到的问题及其解决方法。
  9. Apple Instruments
  10. Aspect Oriented Programming using Interceptors within Castle Windsor and ABP Framework AOP