前言:
前一篇文章中重点总结了一下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: 如有描述错误,请帮忙指正,如果你们有不明白的地方也可以发邮件给我,