保存到桌面加入收藏设为首页
java开发
当前位置:首页 > java开发

$.when(deferreds)-安度博客

时间:2019-02-04 14:52:53   作者:   来源:   阅读:150   评论:0
内容摘要:作者:禅楼望月( http://www.cnblogs.com/yaoyinglong )1 引子上一篇博文中先容的Deferred,它体现一个延迟工具。可是许多时候,我们需要在多个延迟工具(异步代码)都执行完后再去执行另一段代码,这种情况下,使用Deferred就行不通了,就需......
  • 作者:禅楼望月( http://www.cnblogs.com/yaoyinglong )

    1 引子

    上一篇博文中先容的Deferred,它体现一个延迟工具。可是许多时候,我们需要在多个延迟工具(异步代码)都执行完后再去执行另一段代码,这种情况下,使用Deferred就行不通了,就需要使用这里的$.when。

    [+]view code
    word-break: normal; color: ; line-height: normal; background-color: #101020">var wait1=$.Deferred() wait2=$.Deferred();wait1.done(function () { console.log('wait1-success');});wait2.done(function () { console.log('wait2-success');});setTimeout(function () { wait1.resolve();}1000);setTimeout(function () { wait2.resolve();}2000);$.when(wait1wait2) .done(function () { console.log('both wait1 and wait2 are success') });

    image

    [+]view code
    word-break: normal; color: ; line-height: normal; background-color: #101020">var wait1=$.Deferred() wait2=$.Deferred();wait1.fail(function () { console.log('wait1-fail');});wait2.fail(function () { console.log('wait2-fail');});setTimeout(function () { wait1.reject();}1000);setTimeout(function () { wait2.reject();}2000);$.when(20wait1wait2) .fail(function () { console.log('fail'); });

    image

    可以看出,要触发done,必须当所有的Deferred都触发resolve,而要触发fail,只要任意一个Deferred触发reject即可。$.when的用途就是来治理多个延迟工具,其他只传一个Deferred或者通报的不是延迟工具。都是没什么意义的,并不代表会堕落哦。

    2 源码剖析

    在开始源码分析之前,我们先想一想,让我们自己实现这个$.when,应该怎么来实现。首先它肯定是个延迟工具,然后呢,它要等所有的Deferred都触发resolve它才触发resolve,所以需要一个计数器,计数器初始值为参数的个数,某个Deferred触发resolve时,我们就让计数器减1,某个Deferred触发reject时,我们就将计数器置零。然后调用相应的done或者fail,即可。那我们来看jQuery值怎么实现的。

    2.1 工具构建

    逐行分析:

    remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0

    当只有一个参数,判断它是不是Deferred,不是的话让计数器为0。其他情况计数器都即是参数的个数。这里忽略了其他参数不为Deferred的情况,而是将处置惩罚放在后面举行。

    deferred = remaining === 1 ? subordinate : jQuery.Deferred()

    如果现在检测出只有一个Deferred时(这种情况就是when的参数只有一个,而且为Deferred),when内部就是用这个Deferred。就如我上面所说的,这样做就没有任何意义了。只是让JS引擎多跑了几个弯而已。如果有多个Deferred,则建设一个新的Deferred。

    接下来建设了一个名为updateFunc的函数,它是在执行期执行的,这里跳过。

     

    [+]view code
    if ( 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判断when有没有参数通报进来,其实这里没须要判断length,判断remaining就可以了。在if中,使用遍历when的所有参数。发现有不是Deferred的,连忙--remaining。如果参数是Deferred,则为该Deferred的3个状态(resolve,reject,notify)划分注册函数。注册的这3个函数就是用来当通报进来的这些Deferred有相关行动的时候,让when的Deferred获得通知(--remaining或者触发done或者连忙调用fail)。

    if ( !remaining ) { deferred.resolveWith( resolveContexts resolveValues );}

    如果现在判断when的参数中没有Deferred是,直接触发when的resolveWith要领。因此就会触发done要领列表。

    return deferred.promise();

    返回一个精简版的Deferred。主要是为了防止在外部修改了when的Deferred的状态。

    至此,when所对应的延迟工具构建乐成。它是一个不能被修改状态的精简版Deferred。

    2.2 执行期

    执行期没什么内容,就是去执行upateFunc函数。

    [+]view code
    updateFunc = function( i contexts values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; if( values === progressValues ) { deferred.notifyWith( contexts values ); } else if ( !( --remaining ) ) { deferred.resolveWith( contexts values ); } };}

    在前面构建期,为参数Deferred添加注册时间时,done,progress是这样的:

    done( updateFunc( i resolveContexts resolveValues ) )
    progress( updateFunc( i progressContexts progressValues ) )

    然后upateFunc返回一个闭包。闭包中,首先配置values,配置触发resolveWith触发时的参数,这个参数会通报给每一个订阅者。然后判断,如果是progress通报进来的要领,则为触发的是notifyWith。计数器,不做变化,只是调用通知订阅者列表。否则,则先让计数器减减,再判断计数器是否为0,是则触发resolveWith要领。这里的deferred指的是when的Deferred。不能混淆了。

    那如果,when的参数中有一个触发了reject呢?就会直接调用deferred的reject要领。

    fail( deferred.reject )

    因为这里给when的每个Deferred参数的reject添加了一个这样的订阅要领:连忙出发deferred的reject要领。

    总体来说,when的源码照旧较量简朴的。


最近更新

精彩推荐

阅读排行

本站所有站内信息仅供娱乐参考,不作任何商业用途,不以营利为目的,专注分享快乐,欢迎收藏本站!
所有信息均来自:百度一下 (威尼斯人官网)