【原创】jQuery1.8.2源码解析之jQuery.Callbacks

  1 // String to Object options format cache
  2 // 是对option的一个缓存,避免每次都要createOptions
  3 // 每一个option类似这样
  4 // {
  5 //     memory : true
  6 //     ,once : true
  7 //     ,...
  8 // }
  9 var optionsCache = {};
 10 
 11 // Convert String-formatted options into Object-formatted ones and store in cache
 12 function createOptions( options ) {
 13     var object = optionsCache[ options ] = {};
 14     jQuery.each( options.split( core_rspace ), function( _, flag ) {
 15         object[ flag ] = true;
 16     });
 17     return object;
 18 }
 19 
 20 /*
 21  * Create a callback list using the following parameters:
 22  *
 23  *    options: an optional list of space-separated options that will change how
 24  *            the callback list behaves or a more traditional option object
 25  *
 26  * By default a callback list will act like an event callback list and can be
 27  * "fired" multiple times.
 28  *
 29  * Possible options:
 30  *
 31  *    once:            will ensure the callback list can only be fired once (like a Deferred)
 32  *
 33  *    memory:            will keep track of previous values and will call any callback added
 34  *                    after the list has been fired right away with the latest "memorized"
 35  *                    values (like a Deferred)
 36  *
 37  *    unique:            will ensure a callback can only be added once (no duplicate in the list)
 38  *
 39  *    stopOnFalse:    interrupt callings when a callback returns false
 40  *
 41  */
 42 jQuery.Callbacks = function( options ) {
 43 
 44     // Convert options from String-formatted to Object-formatted if needed
 45     // (we check in cache first)
 46     // options也可以是一个对象
 47     options = typeof options === "string" ?
 48         ( optionsCache[ options ] || createOptions( options ) ) :
 49         jQuery.extend( {}, options );
 50 
 51     var // Last fire value (for non-forgettable lists)
 52         memory,
 53         // Flag to know if list was already fired
 54         fired,
 55         // Flag to know if list is currently firing
 56         firing,
 57         // First callback to fire (used internally by add and fireWith)
 58         firingStart,
 59         // End of the loop when firing
 60         firingLength,
 61         // Index of currently firing callback (modified by remove if needed)
 62         firingIndex,
 63         // Actual callback list
 64         list = [],
 65         // Stack of fire calls for repeatable lists
 66         // 只有在没有设置了once时,stack才存在
 67         // stack用来存储参数信息(此时函数列表已经处于firing状态,必须将其他地方调用fire时的参数存储,之后再至此执行fire
 68         stack = !options.once && [],
 69         // Fire callbacks
 70         fire = function( data ) {
 71             // 如果设置memory,那么每一次fire的数据将会被保存在memory中,作为下次调用add时参数
 72             memory = options.memory && data;
 73             fired = true;
 74             firingIndex = firingStart || 0;
 75             // 重置fireStarting为0,因为add操作(memory)可能改变它
 76             firingStart = 0;
 77             firingLength = list.length;
 78             firing = true;
 79             for ( ; list && firingIndex < firingLength; firingIndex++ ) {
 80                 // 如果设置了stopOnFalse参数,那么当函数列表中有某个函数返回false时,停止后面函数的执行,并且取消memory(如果设置了)
 81                 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
 82                     memory = false; // To prevent further calls using add
 83                     break;
 84                 }
 85             }
 86             firing = false;
 87             if ( list ) {
 88                 // 如果stack存在,那么将之前存储的第一个参数取出,继续fire,直到stack为空
 89                 if ( stack ) {
 90                     if ( stack.length ) {
 91                         fire( stack.shift() );
 92                     }
 93                 // 如果stack不存在(即设置了once)
 94                 // 那么如果设置了memory,那么将之前函数列表清空,也就是说memory还在,add操作可以触发函数立即执行
 95                 } else if ( memory ) {
 96                     list = [];
 97                 } else {
 98                     self.disable();
 99                 }
100             }
101         },
102         // Actual Callbacks object
103         // 实际返回的Callbacks对象
104         self = {
105             // Add a callback or a collection of callbacks to the list
106             // 添加函数或者函数集(数组或者伪数组)到函数列表中去
107             add: function() {
108                 if ( list ) {
109                     // First, we save the current length
110                     var start = list.length;
111                     (function add( args ) {
112                         jQuery.each( args, function( _, arg ) {
113                             var type = jQuery.type( arg );
114                             // 如果arg是函数
115                             // 如果设置unique,则在list中查找是否函数已存在,若存在忽略掉,否则push进list
116                             // 如果没有设置unique,则直接push进list
117                             if ( type === "function" && ( !options.unique || !self.has( arg ) ) ) {
118                                 list.push( arg );
119 
120                             // 如果arg是数组或者伪数组,则递归push进list
121                             } else if ( arg && arg.length && type !== "string" ) {
122                                 // Inspect recursively
123                                 // 递归(成员为函数集)
124                                 add( arg );
125                             }
126                         });
127                     })( arguments );
128                     // Do we need to add the callbacks to the
129                     // current firing batch?
130                     // 在添加函数(集)时
131 
132                     // 如果函数列表正在依次执行回调函数(即firing状态),在某一个callback中执行add(fn)操作
133                     // 那么立即修改fireLength以便fire时函数列表能够执行到刚添加的函数(集)
134                     if ( firing ) {
135                         firingLength = list.length;
136                     // With memory, if we're not firing then
137                     // we should call right away
138                     // 如果不是firing状态,并且设置了memory(肯定是在fired状态时才会执行这一步,因为memory是在fire一次后才会被负值)
139                     // 此时memory已经是上次fire是传递的参数,那么将会直接执行刚添加的函数集,而无需fire
140                     } else if ( memory ) {
141                         firingStart = start;
142                         fire( memory );
143                     }
144                 }
145                 return this;
146             },
147             // Remove a callback from the list
148             // 从函数列表中删除函数(集)
149             remove: function() {
150                 if ( list ) {
151                     jQuery.each( arguments, function( _, arg ) {
152                         var index;
153                         // while循环的意义在于借助于强大的jQuery.inArray删除函数列表中相同的函数引用(没有设置unique的情况)
154                         // jQuery.inArray将每次返回查找到的元素的index作为自己的第三个参数继续进行查找,直到函数列表的尽头
155                         // splice删除数组元素,修改数组的结构
156                         while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
157                             list.splice( index, 1 );
158                             // Handle firing indexes
159                             // 在函数列表处于firing状态时,最主要的就是维护firingLength和firgingIndex这两个值
160                             // 保证fire时函数列表中的函数能够被正确执行(fire中的for循环需要这两个值)
161                             if ( firing ) {
162                                 if ( index <= firingLength ) {
163                                     firingLength--;
164                                 }
165                                 if ( index <= firingIndex ) {
166                                     firingIndex--;
167                                 }
168                             }
169                         }
170                     });
171                 }
172                 return this;
173             },
174             // Control if a given callback is in the list
175             // 判断函数列表只能够是否包含给定的fn
176             has: function( fn ) {
177                 return jQuery.inArray( fn, list ) > -1;
178             },
179             // Remove all callbacks from the list
180             // 清空函数列表
181             empty: function() {
182                 list = [];
183                 return this;
184             },
185             // Have the list do nothing anymore
186             // 使函数列表作废(不能再做任何事情)
187             disable: function() {
188                 list = stack = memory = undefined;
189                 return this;
190             },
191             // Is it disabled?
192             // 判断是否函数列表是否disabled
193             disabled: function() {
194                 return !list;
195             },
196             // Lock the list in its current state
197             lock: function() {
198                 stack = undefined;
199                 if ( !memory ) {
200                     self.disable();
201                 }
202                 return this;
203             },
204             // Is it locked?
205             locked: function() {
206                 return !stack;
207             },
208             // Call all callbacks with the given context and arguments
209             // 和fire相似,不相同的是fireWith可以给定上下文参数
210             // fire中就是调用fireWith中的context就是this(函数列表对象self)
211             fireWith: function( context, args ) {
212                 args = args || [];
213                 args = [ context, args.slice ? args.slice() : args ];
214                 // 首先至少fire一次
215                 // 如果执行过一次了(fired),那么若stack存在(即没有设置once),将上下文环境和参数存储,否则什么都不做
216                 if ( list && ( !fired || stack ) ) {
217                     if ( firing ) {
218                         stack.push( args );
219                     } else {
220                         fire( args );
221                     }
222                 }
223                 return this;
224             },
225             // Call all the callbacks with the given arguments
226             // 依次执行函数列表中的函数
227             fire: function() {
228                 self.fireWith( this, arguments );
229                 return this;
230             },
231             // To know if the callbacks have already been called at least once
232             // 判断是否函数列表fire过(哪怕只有一次)
233             fired: function() {
234                 return !!fired;
235             }
236         };
237 
238     return self;
239 };
posted @ 2012-10-18 17:24  Lovesueee  阅读(5192)  评论(3编辑  收藏  举报