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

 源码地址

原文地址:https://www.cnblogs.com/mushishi/p/5759307.html