【原创】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 };
分类:
jquery
标签:
jquery
, javascript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!