js-jQuery中的Callbacks、Deferred和When对象详解(2)

来源:互联网 发布:知善恶树 编辑:程序博客网 时间:2024/06/06 00:29

上次只讲到了Deferred的如何组装对应方法和Promise的组成部分,并没有将Deferred的真正核心代码讲解了。今天抽出时间来讲解一下,不废话,直接看then方法:

then: function( /* fnDone, fnFail, fnProgress */ ) {var fns = arguments;return jQuery.Deferred(function( newDefer ) {jQuery.each( tuples, function( i, tuple ) {var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];// deferred[ done | fail | progress ] for forwarding actions to newDeferdeferred[ 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 );}});});fns = null;}).promise();}

then方法绝对是jQuery中高质量的代码了。

先讲下这段代码的设计思路:then方法每次返回一个新Deferred对象的promise对象,在创建新Deferred对象时指定了一个回调函数,新Deferred对象作为参数传到该回调函数中来。在这段回调函数中:给上一个(即旧的)Deferred对象的done|fail|progress的回调列表中添加函数——该函数会调用then的传入参数的函数,同时判断该函数的返回值,如果是一个promise对象则将新Deferred对象的调用加入到该promise的回调列表中(也就是会在该promise对象notify|resolve|reject时进行调用),否则调用新的Deferred对象的回调列表并将返回值returned作为参数传递。

再说得简单点就是:每次调用then方法会返回产生新的deferred对象,同时then指定的参数会添加到旧的deferred的回调列表中进行链式调用then方法时,会产生多个deferred对象,每个deferred对象的闭包中含有上个(即旧的)deferred对象——该对象将then指定的参数添加到回调列表中。最后通过一个的方法把所有对象的操作都串联起来所有的函数操作就可以一个接着一个的执行了。


then方法的核心思想就是:通过将新对象的notify|resolve|reject方法添加到旧对象对应的progress|done|fail中去,将所有对象的操作串联起来。每次then方法产生的新对象将保存自身的状态。

以上就是then方法也就是Deferred的管道流了。


再看when方法:

// Deferred helperwhen: function( subordinate /* , ..., subordinateN */ ) {var i = 0,resolveValues = slice.call( arguments ),length = resolveValues.length,// the count of uncompleted subordinatesremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,// the master Deferred. If resolveValues consist of only a single Deferred, just use that.deferred = remaining === 1 ? subordinate : jQuery.Deferred(),// Update function for both resolve and progress valuesupdateFunc = function( i, contexts, values ) {return function( value ) {contexts[ i ] = this;values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;if ( values === progressValues ) {deferred.notifyWith( contexts, values );} else if ( !(--remaining) ) {deferred.resolveWith( contexts, values );}};},progressValues, progressContexts, resolveContexts;// add listeners to Deferred subordinates; treat others as resolvedif ( length > 1 ) {progressValues = new Array( length );progressContexts = new Array( length );resolveContexts = new Array( length );for ( ; i < length; i++ ) {if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {resolveValues[ i ].promise().done( updateFunc( i, resolveContexts, resolveValues ) ).fail( deferred.reject ).progress( updateFunc( i, progressContexts, progressValues ) );} else {--remaining;}}}// if we're not waiting on anything, resolve the masterif ( !remaining ) {deferred.resolveWith( resolveContexts, resolveValues );}return deferred.promise();}
相对来说when方法看起来要直观的多,用起来也算简单,when方法常用于合并多个异步操作

通过给resolveValues的promise添加对应的done|fail|progress回调列表中添加updateFunc方法去改变remaining数量,如果remaining为0时则调用主deferred对象的resolveWith触发自己绑定的异步操作全部执行完毕后的函数操作,如果失败则触发主deferred对象的reject,同样触发自己绑定的失败函数操作。

相对来说when方法要简单、直观得多,也比较好理解。也算我偷个懒,when方法就讲到这里。


有其他疑问或错误之处欢迎之处~

允许转载,但请带上出处:http://blog.csdn.net/z905951024  by denied.


以上。


0 0
原创粉丝点击