Callback模块是用来管理回调函数,也做为deferred延迟对象得基础部分,如今一块儿来看看他的源码。
可选参数:java
Options: once: 是否最多执行一次, memory: 是否记住最近的上下文和参数 stopOnFalse: 当某个回调函数返回false时中断执行 unique: 相同得回调只被添加一次
这是可选参数,下面能够进行试验:数组
var a = function (value) { console.log('a:' + value); }; var b = function (value) { console.log('b:' + value); }; var callbacks = $.Callbacks(); callbacks.add(a); callbacks.fire(['hello']); callbacks.add(b); callbacks.fire('中');
下面是他的输出结果:缓存
a: hello, a:中, b:中
能够看到得是,当咱们第二次fire得时候,a函数也会执行。
在加入参数进行实验,首先加入memoryapp
var callbacks = $.Callbacks({ memory: true }); callbacks.add(a); callbacks.fire('hello'); callbacks.add(b); 输出: a:hello, b:hello
加入memory参数,memory记录上一次触发回调函数,以后添加的函数都用这参数当即执行。在来看once的使用函数
var callbacks = $.Callbacks({ once: true }); callbacks.add(a); callbacks.fire('hello'); callbacks.fire('中'); 输出: a:hello
能够看到的是,虽然执行了两次fire方法,可是只输出了一次结果。其余两个参数很好理解,细节的部分本身去尝试。this
$.Callbacks = function(options) { options = $.extend({}, options) var memory, fired, firing, firingStart, firingLength, firingIndex, list = [], stack = !options.once && [] }
再看看各个参数的意义,memory会在记忆模式下记住上一次触发的上下文和参数,fired表明回调是否已经触发过,firing表示回调正在触发,firingStart回调任务开始的位置,firingLength回调任务的长度,firingIndex当前回调的索引,list表示真实的回调队列,在不是触发一次的状况下,用来缓存触发过程当中没有执行的任务参数。code
fire = function(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) { memory = false break } } firing = false if (list) { if (stack) stack.length && fire(stack.shift()) else if (memory) list.length = 0 else Callbacks.disable() } }
fire函数是惟一内置的函数,他的做用是用于触发list的回调执行,首先看看他传进的参数,和我们在外部调用$.Callbacks的fire还不太同样,这里的data是一个数组,data[0]表示上下文,data[1]是方法调用的参数。而后就是各个参数的的初始化,memory表示若是options.memory为true,则保存data,fired为true,若是firingStart为0,那么firingIndex 为0,firingStart置为0,正在触发的回调标记firing为true。
而后遍历回调列表,逐个执行回调,这个里边的if判断表示的是若是回调函数返回的是false而且options.stopOnFalse是false,则清空memory的缓存。遍历完成后,将执行的状态改成false。若是list存在,stack也存在,把任务参数取出来,调用fire函数执行。若是memory存在,则清空列表,不然进行回调执行对象
最终这个文件返回的是Callbacks,咱们来看看他的具体实现:索引
Callbacks = { add: function () { if (list) { var start = list.length, add = function (args) { $.each(args, funciton(_, arg) { if (typeof arg === 'function') { if (!options.unique || !Callbacks.has(arg)) list.push(arg); } else if (arg && arg.length && typeof arg !== 'string') add(arg); }) } add(arguments) if (firing) firingLength = list.length; else if (memory) { firingStart = start; fire(memory) } } return this; } }
这个函数主要的做用就是像list里边push回调。首先判断list是否存在,若是存在,start赋值为list的长度,在内部添加一个add方法,内部add方法主要是向list添加回调,若是咱们传入的参数是数组,就再次调用add方法。而后就是调用add方法,把arguments传进去。若是回调正在进行,则修正回调任务的长度firingLength为当前任务列表的长度,以便后续添加的回调函数能够执行。若是memory存在,则把开始设置为新添加列表的第一位,而后调用fire。
咱们再来看看fireWith的作法:队列
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; }
传入的参数包括上下文,和参数列表。函数执行的条件是list存在而且回调没有执行或者stack存在,stack能够为空。首先对args进行从新赋值,args[0]是上下文,args[1]是复制过来的列表。若是回调正在进行,向stack里边添加args,或者就执行args。