【原創】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 };


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM