jQuery源码学习之Callbacks()
程序员文章站
2022-06-21 16:50:50
jquery.callbacks()是在版本1.7中新加入的。它是一个多用途的回调函数列表对象,提供了一种强大的方法来管理回调函数队列。
1、使用场景:
var callbacks = $.ca...
jquery.callbacks()是在版本1.7中新加入的。它是一个多用途的回调函数列表对象,提供了一种强大的方法来管理回调函数队列。
1、使用场景:
var callbacks = $.callbacks(); callbacks.add(function() { alert('a'); }) callbacks.add(function() { alert('b'); }) callbacks.fire(); //输出结果: 'a' 'b'
便捷的处理参数
once: 确保这个回调列表只执行( .fire() )一次(像一个递延 deferred).
memory: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 deferred).
unique: 确保一次只能添加一个回调(所以在列表中没有重复的回调).
stoponfalse: 当一个回调返回false 时中断调用
例如:
var callbacks = $.callbacks('once'); callbacks.add(function() { alert('a'); }) callbacks.add(function() { alert('b'); }) callbacks.fire(); //输出结果: 'a' 'b' callbacks.fire(); //未执行
2、jquery.callbacks()的api:
callbacks.add() 回调列表中添加一个回调或回调的集合。 callbacks.disable() 禁用回调列表中的回调 callbacks.disabled() 确定回调列表是否已被禁用。 callbacks.empty() 从列表中删除所有的回调. callbacks.fire() 用给定的参数调用所有的回调 callbacks.fired() 访问给定的上下文和参数列表中的所有回调。 callbacks.firewith() 访问给定的上下文和参数列表中的所有回调。 callbacks.has() 确定列表中是否提供一个回调 callbacks.lock() 锁定当前状态的回调列表。 callbacks.locked() 确定回调列表是否已被锁定。 callbacks.remove() 从回调列表中的删除一个回调或回调集合。
分析:
jquery.callbacks = function(options) { // convert options from string-formatted to object-formatted if needed // (we check in cache first) //通过字符串在optionscache寻找有没有相应缓存,如果没有则创建一个,有则引用 //如果是对象则通过jquery.extend深复制后赋给options。 options = typeof options === "string" ? (optionscache[options] || createoptions(options)) : jquery.extend({}, options); var // last fire value (for non-forgettable lists) memory, // 最后一次触发回调时传的参数 // flag to know if list was already fired fired, // 列表中的函数是否已经回调至少一次 // flag to know if list is currently firing firing, // 列表中的函数是否正在回调中 // first callback to fire (used internally by add and firewith) firingstart, // 回调的起点 // end of the loop when firing firinglength, // 回调时的循环结尾 // index of currently firing callback (modified by remove if needed) firingindex, // 当前正在回调的函数索引 // actual callback list list = [], // 回调函数列表 // stack of fire calls for repeatable lists stack = !options.once && [], // 可重复的回调函数堆栈,用于控制触发回调时的参数列表 // fire callbacks// 触发回调函数列表 fire = function(data) { //如果参数memory为true,则记录data memory = options.memory && data; fired = true; //标记触发回调 firingindex = firingstart || 0; firingstart = 0; firinglength = list.length; //标记正在触发回调 firing = true; for (; list && firingindex < firinglength; firingindex++) { if (list[firingindex].apply(data[0], data[1]) === false && options.stoponfalse) { // 阻止未来可能由于add所产生的回调 memory = false; // to prevent further calls using add break; //由于参数stoponfalse为true,所以当有回调函数返回值为false时退出循环 } } //标记回调结束 firing = false; if (list) { if (stack) { if (stack.length) { //从堆栈头部取出,递归fire fire(stack.shift()); } } else if (memory) { //否则,如果有记忆 list = []; } else { //再否则阻止回调列表中的回调 self.disable(); } } }, // actual callbacks object // 暴露在外的callbacks对象,对外接口 self = { // add a callback or a collection of callbacks to the list add: function() { // 回调列表中添加一个回调或回调的集合。 if (list) { // first, we save the current length //首先我们存储当前列表长度 var start = list.length; (function add(args) { //jquery.each,对args传进来的列表的每一个对象执行操作 jquery.each(args, function(_, arg) { var type = jquery.type(arg); if (type === "function") { if (!options.unique || !self.has(arg)) { //确保是否可以重复 list.push(arg); } //如果是类数组或对象,递归 } else if (arg && arg.length && type !== "string") { // inspect recursively add(arg); } }); })(arguments); // do we need to add the callbacks to the // current firing batch? // 如果回调列表中的回调正在执行时,其中的一个回调函数执行了callbacks.add操作 // 上句话可以简称:如果在执行callbacks.add操作的状态为firing时 // 那么需要更新firinglength值 if (firing) { firinglength = list.length; // with memory, if we're not firing then // we should call right away } else if (memory) { //如果options.memory为true,则将memory做为参数,应用最近增加的回调函数 firingstart = start; fire(memory); } } return this; }, // remove a callback from the list // 从函数列表中删除函数(集) remove: function() { if (list) { jquery.each(arguments, function(_, arg) { var index; // while循环的意义在于借助于强大的jquery.inarray删除函数列表中相同的函数引用(没有设置unique的情况) // jquery.inarray将每次返回查找到的元素的index作为自己的第三个参数继续进行查找,直到函数列表的尽头 // splice删除数组元素,修改数组的结构 while ((index = jquery.inarray(arg, list, index)) > -1) { list.splice(index, 1); // handle firing indexes // 在函数列表处于firing状态时,最主要的就是维护firinglength和firgingindex这两个值 // 保证fire时函数列表中的函数能够被正确执行(fire中的for循环需要这两个值 if (firing) { if (index <= firinglength) { firinglength--; } if (index <= firingindex) { firingindex--; } } } }); } return this; }, // check if a given callback is in the list. // if no argument is given, return whether or not list has callbacks attached // 回调函数是否在列表中. has: function(fn) { return fn ? jquery.inarray(fn, list) > -1 : !! (list && list.length); }, // remove all callbacks from the list // 从列表中删除所有回调函数 empty: function() { list = []; firinglength = 0; return this; }, // have the list do nothing anymore // 禁用回调列表中的回调。 disable: function() { list = stack = memory = undefined; return this; }, // is it disabled? // 列表中否被禁用 disabled: function() { return !list; }, // lock the list in its current state // 锁定列表 lock: function() { stack = undefined; if (!memory) { self.disable(); } return this; }, // is it locked? // 列表是否被锁 locked: function() { return !stack; }, // call all callbacks with the given context and arguments // 以给定的上下文和参数调用所有回调函数 firewith: function(context, args) { if (list && (!fired || stack)) { args = args || []; args = [context, args.slice ? args.slice() : args]; //如果正在回调 if (firing) { //将参数推入堆栈,等待当前回调结束再调用 stack.push(args); } else { //否则直接调用 fire(args); } } return this; }, // call all the callbacks with the given arguments // 以给定的参数调用所有回调函数 fire: function() { self.firewith(this, arguments); return this; }, // to know if the callbacks have already been called at least once // // 回调函数列表是否至少被调用一次 fired: function() { return !!fired; } }; return self; };
jquery.callbacks()的核心思想是 pub/sub 模式,建立了程序间的松散耦合和高效通信。
pub/sub (观察者模式) 的背后,总的想法是在应用程序中增强松耦合性。并非是在其它对象的方法上的单个对象调用。一个对象作为特定任务或是另一对象的活动的观察者,并且在这个任务或活动发生时,通知观察者。观察者也被叫作订阅者(subscriber),它指向被观察的对象,既被观察者(publisher 或 subject)。当事件发生时,被观察者(publisher)就会通知观察者(subscriber)。
上一篇: 从学者的角度分析谁适合学习编程语言