zoukankan      html  css  js  c++  java
  • 【原创】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 };
  • 相关阅读:
    00077_集合
    python、js、php区别---6、函数相关
    python、js、php区别---5、存储结构
    python、js、php区别---4、基本结构
    python、js、php区别---3、运算符
    python、js、php区别---2、数据类型
    python、js、php区别---1、基本区别
    python疑难问题---3、可变和不可变数据类型
    python疑难问题---2、字典排序
    python疑难问题---1、遍历列表的三种方式
  • 原文地址:https://www.cnblogs.com/lovesueee/p/2729829.html
Copyright © 2011-2022 走看看