• jQuery源码分析之Callbacks方法


      1 // String to Object flags format cache
      2 // 我们暂且称flagsCache为行为标识符串信息集合,供jQuery.Callbacks函数使用
      3 // flagCache存储信息格式如下:
      4 // {'once':{'once':true},'once memory':{'once':true,'memory':true}}
      5 // 其中key为行为标识符串,value为行为标识符串所包含的行为标识符的信息对象
      6 // 行为标识符串是由空格隔开的多个行为标识符构成的字符串
      7 // 行为标识符则是影响队列里的回调函数执行方式的字符串
      8 var flagsCache = {};
      9 
     10 // Convert String-formatted flags into Object-formatted ones and store in cache
     11 // 将行为标识符串转换成对象存储到flagsCache中,供jQuery.Callbacks函数使用
     12 function createFlags( flags ) {
     13     var object = flagsCache[ flags ] = {},
     14            i, length;
     15            flags = flags.split( /s+/ );
     16     for ( i = 0, length = flags.length; i < length; i++ ) {
     17         object[ flags[i] ] = true;
     18     }
     19     return object;
     20 }
     21 
     22 /*
     23  * Create a callback list using the following parameters:
     24  *flags:an optional list of space-separated flags that will change how
     25  *the callback list behaves
     26  * By default a callback list will act like an event callback list and can be
     27  * "fired" multiple times.
     28  * Possible flags:
     29  *once:will ensure the callback list can only be fired once (like a Deferred)
     30  *
     31  *memory:  will keep track of previous values and will call any callback added
     32  *  after the list has been fired right away with the latest "memorized"
     33  *  values (like a Deferred)
     34  *
     35  *unique:  will ensure a callback can only be added once (no duplicate in the list)
     36  *
     37  *stopOnFalse: interrupt callings when a callback returns false
     38  */
     39  //以上英文为jQuery自带API说明,现用自己的语言说明一下:
     40  //该函数将创建用于管理回调函数列表的对象
     41  //参数flags为行为标识字符串,是由空格隔开的多个行为标识符构成的字符串。
     42  //默认情况下(即不传flags),则回调函数列表如同事件回调函数列表般执行。
     43  //flags可能的值:
     44  //(1)once:该行为标识符表示列表中的回调函数仅执行一次
     45  //(2)memory:该行为标识符表示会将先前执行回调函数用到的值(context和args)放入栈中缓存
     46  //(3)unique:该行为标识符表示确保放入列表中的回调函数唯一性
     47  //(4)stopOnFalse:该行为标识符表示当执行列表中的回调函数返回false时将中断后面的回调函数执行
     48 jQuery.Callbacks = function( flags ) {
     49     // Convert flags from String-formatted to Object-formatted
     50     // (we check in cache first)
     51     // 获取行为标识符信息对象
     52     flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
     53 
     54     var // Actual callback list
     55     // 存放回调函数的列表
     56     list = [],
     57     // Stack of fire calls for repeatable lists
     58     // 存放调用回调函数所需参数(context和args)放入队列中
     59     stack = [],
     60     // Last fire value (for non-forgettable lists)
     61     // 缓存最近一次执行回调函数列表所用到的值(context和args)
     62     memory,
     63     // Flag to know if list is currently firing
     64     // 标记是否回调函数列表正在执行
     65     firing,
     66     // First callback to fire (used internally by add and fireWith)
     67     // 标记回调函数列表执行开始的下标值
     68     firingStart,
     69     // End of the loop when firing
     70     // 标记回调函数列表执行结束的下标值
     71     firingLength,
     72     // Index of currently firing callback (modified by remove if needed)
     73     // 标记回调函数列表正在执行的下标值
     74     firingIndex,
     75     // Add one or several callbacks to the list
     76     // 向回调函数列表添加函数
     77     add = function( args ) {
     78         var i,
     79             length,
     80             elem,
     81             type,
     82             actual;
     83         for ( i = 0, length = args.length; i < length; i++ ) {
     84             elem = args[ i ];
     85             type = jQuery.type( elem );
     86             if ( type === "array" ) {
     87                 // Inspect recursively
     88                 // 若元素是数组,则递归,直到元素类型为方法时才放入列表中
     89                 add( elem );
     90             } else if ( type === "function" ) {
     91                 // Add if not in unique mode and callback is not in
     92                 // 直到elem为方法时,
     93                 // 判断unique标识符是否传入,若是则需判断elem是否已存在列表中;
     94                 // 若非唯一,则执行将elem放入列表中。
     95                 if ( !flags.unique || !self.has( elem ) ) {
     96                     list.push( elem );
     97                 }
     98             }
     99         }
    100     },
    101     // Fire callbacks
    102     // 执行回调函数列表
    103     // context为上下文环境,必选
    104     // args为传入回调函数参数,可选
    105     fire = function( context, args ) {
    106         args = args || [];
    107         //判断memory标识符是否传入,
    108         //如是则memory=[context, args],
    109         //若非则memory=true
    110         memory = !flags.memory || [ context, args ];
    111         //标记列表正在执行
    112         firing = true;
    113         //标记列表执行正在执行的下标值
    114         firingIndex = firingStart || 0;
    115         //重置列表执行开始位的下标值
    116         firingStart = 0;
    117         //标记列表执行长度
    118         firingLength = list.length;
    119         for ( ; list && firingIndex < firingLength; firingIndex++ ) {
    120             //需判断stopOnFalse标识符是否传入,
    121             //如是则在执行回调函数返回false时中断列表后面的回调函数执行并标记memory=true
    122             if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
    123                 memory = true; // Mark as halted
    124                 break;
    125             }
    126         }
    127         //标记列表执行完毕
    128         firing = false;
    129         if ( list ) {
    130             //判断once行为标识符是否传入
    131             if ( !flags.once ) {
    132                 //未传入once行为标识符则判断队列stack是否存值
    133                 if ( stack && stack.length ) {
    134                     //弹出队列的第一个元素作为调用回调函数列表所需参数(context和args)传入
    135                     memory = stack.shift();
    136                     self.fireWith( memory[ 0 ], memory[ 1 ] );
    137                 }
    138             } else if ( memory === true ) {
    139                 //传入once行为标识符,并且memory=true。
    140                 //执行列表的回调函数后,memory=true只有两种情况:
    141                 //1、memory标识符未传入(即行为标识符串flags包含有memory)。
    142                 //2、stopOnFalse标识符传入(即行为标识符串(flags)包含有stopOnFalse),
    143                 //并且执行列表回调函数时返回false。
    144                 //此时回调函数列表将被冻结使用,即后面对该列表任何操作都将失效。
    145                 self.disable();
    146             } else {
    147                 //传入once行为标识符,则置空回调函数列表
    148                 list = [];
    149             }
    150         }
    151     },
    152     // Actual Callbacks object
    153     // self为函数jQuery.Callbacks所要返回的对象,其实它是闭包。
    154     // 函数外部是无法访问的函数jQuery.Callbacks内的变量和函数的。
    155     // 为了能够提供外部操作回调函数列表,故将self对象返回。
    156     // self对象的一些方法返回this的目的是为了能够链式调用,这是一个技巧。
    157     self = {
    158         // Add a callback or a collection of callbacks to the list
    159         // 添加回调函数到列表中
    160         add: function() {
    161             if ( list ) {
    162                 var length = list.length;
    163                 //调用上面定义的add函数
    164                 add( arguments );
    165                 // Do we need to add the callbacks to the
    166                 // current firing batch?
    167                 // 判断回调函数列表是否正在执行
    168                 if ( firing ) {
    169                     //如是,则需将firingLength重置为添加元素后的列表长度
    170                     //新增的回调函数能够被执行到,具体原因见上面的函数fire实现
    171                     firingLength = list.length;
    172                 } 
    173                 // 如非,则判断memory是否缓存有最近一次执行回调函数列表时所用的值(context和args)
    174                 else if ( memory && memory !== true ) {
    175                     // With memory, if we're not firing then
    176                     // we should call right away, unless previous
    177                     // firing was halted (stopOnFalse)
    178                     // 如是,则将回调函数列表执行的开始下标设置为新增的元素下标值,
    179                     // 并将memory缓存的两个值作为参数传给fire函数调用
    180                     firingStart = length;
    181                     fire( memory[ 0 ], memory[ 1 ] );
    182                 }
    183             }
    184             return this;
    185         },
    186         // Remove a callback from the list
    187         // 移除指定回调函数列表中指定的元素
    188         remove: function() {
    189             if ( list ) {
    190                 var args = arguments,
    191                 argIndex = 0,
    192                 argLength = args.length;
    193                 for ( ; argIndex < argLength ; argIndex++ ) {
    194                     // 删除指定的元素值每次都需遍历一遍回调函数列表list
    195                     for ( var i = 0; i < list.length; i++ ) {
    196                         if ( args[ argIndex ] === list[ i ] ) {
    197                             // Handle firingIndex and firingLength
    198                             // 若回调函数列表正在执行中
    199                             // 则需相应的设置firingIndex和firingLength的值
    200                             if ( firing ) {
    201                                 if ( i <= firingLength ) {
    202                                     firingLength--;
    203                                     if ( i <= firingIndex ) {
    204                                         firingIndex--;
    205                                     }
    206                                 }
    207                             }
    208                             // Remove the element
    209                             // 由于执行splice列表的元素值将减1
    210                             // 所以当删除操作执行完后索引变量i也需减1
    211                             list.splice( i--, 1 );
    212                             // If we have some unicity property then
    213                             // we only need to do this once
    214                             // 判断unique行为标识符是否传入
    215                             // 如是则无需继续遍历查询需删除的元素是否在列表中
    216                             // 因为unique行为标识符已确保列表中元素的唯一性
    217                             // 这是一个技巧
    218                             if ( flags.unique ) {
    219                                 break;
    220                             }
    221                         }
    222                     }
    223                 }
    224             }
    225             return this;
    226         },
    227         // Control if a given callback is in the list
    228         // 检测是否回调函数队列中是否已包含有指定回调函数
    229         has: function( fn ) {
    230             if ( list ) {
    231                 var i = 0,
    232                 length = list.length;
    233                 for ( ; i < length; i++ ) {
    234                     if ( fn === list[ i ] ) {
    235                         return true;
    236                     }
    237                 }
    238             }
    239             return false;
    240         },
    241         // Remove all callbacks from the list
    242         // 置空回调函数队列list
    243         empty: function() {
    244             list = [];
    245             return this;
    246         },
    247         // Have the list do nothing anymore
    248         // 调用次函数后,终结对回调函数列表的任何操作
    249         disable: function() {
    250             list = stack = memory = undefined;
    251             return this;
    252         },
    253         // Is it disabled?
    254         disabled: function() {
    255             return !list;
    256         },
    257         // Lock the list in its current state
    258         // 锁住回调函数列表的当前调用状态(context和args)
    259         lock: function() {
    260             stack = undefined;
    261             if ( !memory || memory === true ) {
    262                 self.disable();
    263             }
    264             return this;
    265         },
    266         // Is it locked?
    267         // 判定是否已锁住回调函数列表的当前调用状态(context和args)
    268         locked: function() {
    269             return !stack;
    270         },
    271         // Call all callbacks with the given context and arguments
    272         // 使用指定的参数(context和args)调回调函数列表
    273         fireWith: function( context, args ) {
    274             if ( stack ) {
    275                 if ( firing ) {
    276                    //若回调函数列表正在执行
    277                     if ( !flags.once ) {
    278                         //若未传入once行为标识符
    279                         //由于回调函数列表正在执行,
    280                         //所以回调函数列表不能立即使用传入的参数(context和args)执行,
    281                         //需要将传入的参数(context和args)存入队列stack中。
    282                         //当回调函数列表执行完毕后,将会逐一使用队列stack中的值再执行回调函数列表,直到队列stack没有元素为止
    283                         //具体请参看fire函数
    284                         stack.push( [ context, args ] );
    285                     }
    286                 } else if ( !( flags.once && memory ) ) {
    287                     //若回调函数列表已执行完毕,则直接使用传入的参数(context和args)调用回调函数列表
    288                     fire( context, args );
    289                 }
    290             }
    291             return this;
    292         },
    293         // Call all the callbacks with the given arguments
    294         // fire方法是fireWith的特殊化,将fire方法的调用对象即self本身作为context传入fireWith方法中
    295         fire: function() {
    296             self.fireWith( this, arguments );
    297             return this;
    298         },
    299         // To know if the callbacks have already been called at least once
    300         fired: function() {
    301             return !!memory;
    302         }
    303     };
    304     return self;
    305 };
  • 相关阅读:
    Kafka相关知识点
    好的前端界面
    linux下配置go环境
    插入排序(数据是局部有序的)
    选择排序
    spring jpa 条件查询统计
    java代码优化
    JAVA创建临时文件IO
    spring防止表单重复提交
    Java文件下载时所输出文件名乱码问题
  • 原文地址:https://www.cnblogs.com/bender/p/3361142.html
Copyright © 2020-2023  润新知