• jQuery.callbacks 注释


      1 (function( jQuery ) {
      2 
      3 // String to Object flags format cache
      4 var flagsCache = {};
      5 
      6 // Convert String-formatted flags into Object-formatted ones and store in cache
      7 // 将字符串形式的flags转换成对象形式,并且存到cache中,例: "once memory" =>  {"once":true,"memory":true}
      8 function createFlags( flags ) {
      9     var object = flagsCache[ flags ] = {},
     10         i, length;
     11     flags = flags.split( /s+/ );
     12     for ( i = 0, length = flags.length; i < length; i++ ) {
     13         object[ flags[i] ] = true;
     14     }
     15     return object;
     16 }
     17 
     18 /*
     19  * 用以下参数创建一个回调函数列表:
     20  *
     21  *    flags:    可选的以空格分隔的flags,会影响回调函数列表的行为
     22  *     
     23  *
     24  * 默认情况下,回调函数列表的行为如同一个事件回调函数列表一样,并且可以触发多次。 
     25  *
     26  * 可选的 flags:
     27  *
     28  *    once:            会确保回调列表只被触发一次(像Deferred一样), 这个不会阻止memory模式,也就是说 "once memory"的参数下 虽然只能fire一次,但是fire后再add 还是有效果的
     29  *
     30  *    memory:          会记录上一次fire的上下文(一般是$.callbacks自身)和参数,并且会立即以最近一次fire记录下的上下文和参数执行新添加进来回调函数 (像Deferred一样)
     31  *                     具体看 (1) 88行 memory = !flags.memory || [ context, args ];  保存memory模式下的 函数上下文和参数
     32  *                           (2) 127-130行 self.add添加回调函数时候的处理
     33  *
     34  *    unique:          会确同一个回调函数只在列表中出现一次
     35  *
     36  *    stopOnFalse:     其中一个回调函数返回false即停止调用其余函数
     37  *
     38  */
     39 jQuery.Callbacks = function( flags ) {
     40 
     41     // Convert flags from String-formatted to Object-formatted
     42     // (we check in cache first)
     43     flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
     44 
     45     var // 实际存放回调函数的容器
     46         list = [],
     47 
     48         // 用以存放可重复fire(即非once模式),重复fire的回调函数  例: 在一个回调函数体里边也调用了fire的情景 
     49         // 另外这个stack 还用以标示整个回调列表是否处于锁定状态(仅仅判可不可触发fire, 还是可以add, remove的)  205行 + 192-202行
     50         stack = [],
     51 
     52         // 上次fire的上下文和参数, 
     53         // 可能的值: (1) [context,args]
     54         //          (2) true , 非记忆执行上下文和参数 或者 stopOnFalse模式下有返回为false的回调函数
     55         memory,
     56         // 标识当前是否处于fire状态
     57         firing,
     58         // fire第一个执行的回调函数在list中的索引位置 (内部fireWith使用和add导致list个数变化时修正执行中的索引位置 128行) 
     59         firingStart,
     60         // 循环的结尾位置 (如果在firing状态下self.add添加新函数和self.remove移除函数时候会调整 123行 146行 )
     61         firingLength,
     62         // 当前触发的函数索引 ,需要的时候会调整
     63         firingIndex,
     64         //工具方法: 添加一个或多个(args为数组时)函数到list 
     65         add = function( args ) {
     66             var i,
     67                 length,
     68                 elem,
     69                 type,
     70                 actual;
     71             for ( i = 0, length = args.length; i < length; i++ ) {
     72                 elem = args[ i ];
     73                 type = jQuery.type( elem );
     74                 if ( type === "array" ) {
     75                     // 递归检查
     76                     add( elem );
     77                 } else if ( type === "function" ) {
     78                     // 非unique模式且新回调函数不存在
     79                     if ( !flags.unique || !self.has( elem ) ) {
     80                         list.push( elem );
     81                     }
     82                 }
     83             }
     84         },
     85         //工具方法: 触发回调函数
     86         fire = function( context, args ) {
     87             args = args || [];
     88             memory = !flags.memory || [ context, args ];
     89             firing = true;
     90             firingIndex = firingStart || 0;
     91             firingStart = 0;
     92             firingLength = list.length;
     93             for ( ; list && firingIndex < firingLength; firingIndex++ ) {
     94                  if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
     95                     memory = true; // 标记为终止  注意看106行, 销毁$.callbacks 
     96                     break;
     97                 }
     98             }
     99             firing = false; // 标记执行结束
    100             if ( list ) {
    101                 if ( !flags.once ) { // fire完后检查是否有回调函数内部重复fire保留下来的执行上下文和参数
    102                     if ( stack && stack.length ) {
    103                         memory = stack.shift();
    104                         self.fireWith( memory[ 0 ], memory[ 1 ] );
    105                     }
    106                 } else if ( memory === true ) { // stopOnFalse
    107                     self.disable();
    108                 } else {
    109                     list = [];
    110                 }
    111             }
    112         },
    113         // 实际的回调函数对象
    114         self = {
    115             //实例方法: 添加一个或多个(args为数组时)函数到list 
    116             add: function() {
    117                 if ( list ) {
    118                     var length = list.length;
    119                     add( arguments );
    120                     // Do we need to add the callbacks to the
    121                     // current firing batch?
    122                     if ( firing ) {
    123                         firingLength = list.length;
    124                     // With memory, if we're not firing then
    125                     // we should call right away, unless previous
    126                     // firing was halted (stopOnFalse)
    127                     } else if ( memory && memory !== true ) {
    128                         firingStart = length;
    129                         fire( memory[ 0 ], memory[ 1 ] );
    130                     }
    131                 }
    132                 return this;
    133             },
    134             // 从列表中移除函数 
    135             remove: function() {
    136                 if ( list ) {
    137                     var args = arguments,
    138                         argIndex = 0,
    139                         argLength = args.length;
    140                     for ( ; argIndex < argLength ; argIndex++ ) {
    141                         for ( var i = 0; i < list.length; i++ ) {
    142                             if ( args[ argIndex ] === list[ i ] ) {
    143                                 // 在firing时移除函数,需要修正当前索引firingIndex和长度firingLength
    144                                 if ( firing ) {
    145                                     if ( i <= firingLength ) {
    146                                         firingLength--;
    147                                         if ( i <= firingIndex ) {
    148                                             firingIndex--;
    149                                         }
    150                                     }
    151                                 }
    152                                 // Remove the element
    153                                 list.splice( i--, 1 );
    154                                 // 如果是unique模式(这时不会有重复的函数),移除一次就可以了
    155                                 if ( flags.unique ) {
    156                                     break;
    157                                 }
    158                             }
    159                         }
    160                     }
    161                 }
    162                 return this;
    163             },
    164             // 判断指定回调函数是否存在
    165             has: function( fn ) {
    166                 if ( list ) {
    167                     var i = 0,
    168                         length = list.length;
    169                     for ( ; i < length; i++ ) {
    170                         if ( fn === list[ i ] ) {
    171                             return true;
    172                         }
    173                     }
    174                 }
    175                 return false;
    176             },
    177             // Remove all callbacks from the list
    178             empty: function() {
    179                 list = [];
    180                 return this;
    181             },
    182             // Have the list do nothing anymore
    183             disable: function() {
    184                 list = stack = memory = undefined;
    185                 return this;
    186             },
    187             // Is it disabled?
    188             disabled: function() {
    189                 return !list;
    190             },
    191             // Lock the list in its current state
    192             lock: function() {
    193                 stack = undefined;
    194                 if ( !memory || memory === true ) { 
    195                     self.disable();
    196                 }
    197                 return this;
    198             },
    199             // Is it locked?
    200             locked: function() {
    201                 return !stack;
    202             },
    203             // Call all callbacks with the given context and arguments
    204             fireWith: function( context, args ) {
    205                 if ( stack ) { // stack=[] 也是true  
    206                     if ( firing ) {
    207                         if ( !flags.once ) {
    208                             stack.push( [ context, args ] );
    209                         }
    210                     } else if ( !( flags.once && memory ) ) {
    211                         fire( context, args );
    212                     }
    213                 }
    214                 return this;
    215             },
    216             // Call all the callbacks with the given arguments
    217             fire: function() {
    218                 self.fireWith( this, arguments );
    219                 return this;
    220             },
    221             // To know if the callbacks have already been called at least once
    222             fired: function() {
    223                 return !!memory; // 其实这个有问题, 当调用disable() 的时候 memory==undefined
    224             }
    225         };
    226 
    227     return self;
    228 };
    229 
    230 })( jQuery );

    下面是一些检验这些参数逻辑的代码:

     1      /*
     2              jquery.Callbacks
     3          */
     4          // var testUrl="http://www.runoob.com/try/ajax/demo_test.php";
     5          // var callbacks=new jQuery.Callbacks("memory");
     6          // callbacks.add(function(){alert("first callback")});
     7          // callbacks.add(function(){alert("second callback")});
     8          // callbacks.fire(); 
     9          // memory
    10         // callbacks.add(function(){alert("third callback")});            
    11 
    12 
    13         var callback2=
    14          jQuery.Callbacks("once memory"), // once 表示回调函数列表只会fire一次,但是还会运行memory机制,也不限制回调函数列表里边有多个相同的函数(可以用unique 去重)
    15          something = true;
    16         function fn1(args)
    17         {
    18              alert('fn1 args:'+args);
    19              console.log(this);
    20             if(something){
    21                 callback2.fire(" test:第2次触发");
    22                 callback2.fire(" test:第3次触发"); //fire内部再触发的话 先放入stack中 
    23                 something=false;
    24             }
    25         }
    26         function fn2(){
    27             alert('fn2');
    28         }        
    29         callback2.add(fn1); 
    30         callback2.add(fn2);
    31 
    32         callback2.fire('测试:第1次触发');
    33         callback2.fire('测试:第4次触发');  //once模式 只会fire一次, memory在add的时候促发
    34         callback2.add(fn2);
    View Code

     源码地址

  • 相关阅读:
    苹果系统的时间兼容问题
    WOWJS+animate滚动特效
    js的帧动画
    网页图片透明加载
    文字不可被选中设置属性!
    [转]阻塞IO与非阻塞IO
    死锁
    TCP 三次握手四次挥手
    键入网址后,期间发生了什么
    堆排序
  • 原文地址:https://www.cnblogs.com/mushishi/p/5759307.html
Copyright © 2020-2023  润新知