首页 > 代码库 > jQuery源码解读第5章---对Callbacks的解读
jQuery源码解读第5章---对Callbacks的解读
jQuery.Callbacks() 是一个多用途的回调函数列表对象
提供了一种强大的方法来管理回调函数队列
先来看看Callbacks的常见的用法
1-------不带参数
先看看不用回调函数的例子
eq
function a1(){
console.log(‘a1‘)
}
(function(){
function a2(){
console.log(‘a2‘)
}
})()
a1() // a1
a2() //就不行了
这时候我们就可以使用回调函数Callbacks 了
var dfd1 = $.Callbacks();
function a1(){
console.log(‘a1‘)
}
dfd1.add(a1)
(function(){
function a2(){
console.log(‘a2‘)
}
dfd1.add(a2)
})()
dfd1.fire() // a1 a2
Callbacks提供了一个强大的方法来管理回调函数列表
上面已经说过无参数的情况了
下面来说一说有参数的情况,,,,
jQuery的源码,我们可以看到Callbacks回调函数有参数的情况分为4种 分别为once memory unique stopOnFalse 这四种情况
下文我用例子分别解释一下
1------ once --- 确保这个回调列表只执行一次 (通俗的说fire()这个函数只能执行一次)
eq
var dfd2 = $.Callbacks(‘once‘);
function a1(){
console.log(‘a1‘)
}
dfd2.add(a1)
dfd2.fire();
dfd2.fire();
这样只能执行一个fire()
r如果没有options 为once的话 是会执行两个fire()
2--------unique ---确保一次只能添加一个回调( 也就是只能不能添加相同的函数)
once 和 unique 比较相似,,,,所以我先说
eq
var dfd3 = $.Callbacks(‘unique‘);
function a1(){
console.log(‘a1‘)
}
dfd3.add(a1)
dfd3.add(a1)
dfd3.fire(); //a1
这时候只有一个函数执行而已 ..
3-------- memory --- 就是保持到最后一个add()执行完再执行 ( 其实就是不管fire()在什么地方,,,都会执行完所有回调函数 )
eq
var dfd4 = $.Callbacks(‘memory‘);
function a1(){
console.log(‘a1‘)
}
dfd4.add(a1)
dfd4.fire();// 如果没有options 为memory的话,,,,后面的add 就不会执行了
(function(){
function a2(){
console.log(‘a2‘)
}
dfd2.add(a2)
})()
这时候所有回调函数都会执行
4----- stopOnFalse ----当一个回调函数返回false时候就中断回调
var dfd5 = $.Callbacks(‘stopOnFalse‘);
function a1(){
console.log(‘a1‘);
return false;
}
dfd5.add(a1)
(funciton(){
function a2(){
console.log(‘a2‘)
}
dfd5.add(a2)
})()
dfd5.fire() //如果没有stopOnFalse 和return false 的话,,,,,,这时候 结果应该为 a1 a2 的
但是中断了回调了 ,,,,只出现a1而已
基本的使用情况已经说完,,,,,下面开始解读源码了
当然回调对象Callbacks 还有一些具体的方法 如callbacks.add() callbacks.fire() callbacks.remove()等等
这些我到看到再说,,,,
先看看总体结构,
jQuery.Callbacks = function( options ){ var memory, firing, ...... self = { add: function(){ }, remove : function(){ } ....... } return self; }
//这里就是对options配置参数处理的函数
var optionsCache = {};
我们要明白一点就是 options 配置参数可以是 ‘ once memory ‘ 或者‘once‘这样的
function createOptions( options ){
var object = optionsCache[ options ] ={};
这里我们要用到jQuery.each()这个方法
这个方法的源码,,,,我们还没有学,,,,但是jQuery.each这个工具方法,,是我们平时常用的,,,,我们对这个方法应该很熟悉才对,,,
所以不影响我们的学习
正则match()方法找到符合的,则放到数组,,,,, 如果没有的话,,,就返回null
上面定义好了 core_rnotwhite = /\S+/g ------ >非空字符
jQuery.each( options.match( core_rnotwhite ) || [],function(_,flag){
object[ flag ] = true;
} )
return object;
}
这就是总体结构
jQuery.Callbacks = function( options ){
//对options的处理和判断
options = typeof options === ‘string‘ ?
( optionsCache[ options ] || createOptions(options) ) :
先判断options是否有缓存,,,,有的话,,就不执行createOptions(options)这个函数
jQuery.extend( {}, options ); //这个一般指的是options为空的时候,,,,,如果options是数组或者别的,,,,是无效的
//定义一系列变量
var
memory,firing,fired,firingIndex,firingStart,firingLength,
stack = !options.once && [], //once 存在 ,,stack 为false once不存在,,,,stack 为[]
list =[ ], //定义一个数组用来存放函数
/*******PS 这部分本人建议先看完后面的再回来看 可以先跳过*********************************/
1 fire = function(data){ 2 memory = options.memory && data; //如果存在memory这个配置参数,,,,,,变量memory就为data 3 4 fired = true; //标记已经触发过了 5 6 firingIndex = firingStart || 0; 7 8 firingStart = 0; 9 10 firingLength = list.length; 11 12 firing = true; //标记正在触发回调函数列表 13 14 for( ;firingIndex < firingLength;firingIndex++ ){ 15 if( list[firingIndex].apply(data[0],data[1]) === false && options.stopOnFalse ){ 16 memory = false; 17 break; //退出循环 18 } 19 } 20 21 firing = false; 22 23 if( list ){ 24 if(stack){ 25 if( stack.length ){ 26 fire(stack.shift()) 27 } 28 }else if(memory){ 29 list = [] 30 }else{ 31 self.disable(); 32 } 33 } 34 35 36 37 }
这个fire() 是最终触发回调函数列表的
重点解释
1------> list[ firingIndex ].apply(data[0],data[1])
这段代码即是执行回调函数的
把list里面的每个函数,,,,,放到data[0](即回调对象中)执行 参数为data[1]
同时这里对配置参数stopOnFalse 做了判断
当执行里面的回调函数 ....... 有return false 而且 存在stopOnFalse 这个参数的话...
执行memory = false ;-----> 阻止未来add()中产生的回调
2--------> fire(stack.shift())
当stack.length 不为0 时....说明堆栈有参数
stack.shift() --- 通过使用数组的shift() .....把第一个元素从数组中删除,,,并返回第一个元素
就递归执行fire() 这个函数
/****************************************/
self = {
add : function(){
/*
add方法是回调函数中常用的方法
上面的例子中到用到
*/
if(list){ //list 就算是空数组,,也是true
var start = list.length;
//这里用了一个立即执行的add函数来添加回调 (function add(args){ jQuery.each(args,function(_,arg){ var type = jQuery.type(arg); if( type === ‘function‘ ){ if( !options.unique || !self.has(arg)){ /* !options.unique || !self.has(arg)的意思就是 没有参数unique的话 .......> 直接添加,,,不用判断!self.has(arg) 如果有参数uniqued------> 说明不能添加一样的,,就要判断self.has(arg) self.has(arg) //用于判断回调列表中是否包含arg 通过判断是否有unique 和判断在回调列表中是否存在 就可以知道arg 要不要添加到list中了 */ list.push(arg) }else if( arg && arg.length && type !== ‘string‘){ /* arg && arg.length && type !== ‘string‘这个判断语句 通过判断type !== ‘string‘ 和arg.length 有length这个属性 从而得出是一个数组 eq var cb = $.Callbacks(); function a1(){ console.log(‘a1‘) } function a2(){ console.log(‘a2‘) } cb.add([a1,a2]) cb.fire();// a1 a2 既然是数组,,,,那只能通过递归来添加回调了 */ add(arg) } } }); })(arguments)
}
//便于链式调用
return this;
},
1 remove : function(){ 2 if(list){ 3 jQuery.each(arguments,function(_,arg){ 4 var index; 5 6 while((index = jQuery.inArray(arg,list,index)) > -1){ 7 list.splice(index,1); //用splice()方法删除指定的回调函数 8 if(firing){ 9 /* 10 firing这个变量只有在调用fire() 这个函数是才是true,,,,,,一结束for循环就为false 11 //标记正在触发回调 12 firing = true; 13 14 for(;list&& firingIndex < firingLength;firingIndex++){ 15 if(list[firingIndex].apply(data[0],data[1]) === false && options.stopOnFalse){ 16 ................... 17 } 18 } 19 firing = false; 20 firing 只要回调一结束,,,,,,firing就为false; 21 22 */ 23 24 25 /* 26 如果firing为true时 27 要让函数正确执行,,,,,,就要动态改变firingLength 和 firingIndex 这两个变量 28 */ 29 if(index <= firingLength){ 30 firingLength--; 31 } 32 if(index <= firingIndex){ 33 firingIndex--; 34 } 35 36 37 } 38 } 39 40 41 }) 42 } 43 },
//has() 这个方法比较简单......
//has ----> 判断list是否存在指定回调(fn)
has:function(fn){
return fn ? jQuery.inArray(fn,list) > -1 : !!(list && list.length);
},
//empty() ----顾名思义 就是从列表中删除所有回调函数
empty : function(){
list = [];
firingLength =0;
return this;
},
//禁用回调列表中的回调
disable :function(){
list = stack = memory = undefined;
return this;
},
//判断列表是否被禁用
disabled : function(){
return !list;
},
//锁定列表
lock : function(){
stack = undefined;
if(!memory){
self.disable();
}
return this;
},
//判断列表是否被锁定
locked : function(){
return !stack;
},
//从下文可以得到,,,,,其实调用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; }
这里我会讲解一下args.slice ? args.slice() : args
args.slice 的意思就是判断一下args有没有slice这个方法
有就放回slice()
无则返回args
我们要明白一点就是arguments 不是一个真正的数组,,,,,它是一个类数组,,,,所以没有slice()
上文,,,我已经说过了firing在什么时候为true了
当正在回调时...firing就是true........所以firing 为true ,,那我们就把参数推入堆栈中,,,等当前回调结束再调用
stack.push(args);
如果不是true.....即可直接调用 fire(args)
//调用回调函数
fire : function(){
self.fireWith(this,arguments);
return this;
},
fired: function(){
return !!fired; //判断回调列表是否执行过
}
};
return self;
}
本人才疏学浅,,这里是本人看jQuery源码的一些感悟而已,,,,,如有不对的地方,,,欢迎大家留言指出,,共同进步 或者 发邮件至2240970215@qq.com
PS: 路过留点痕。。
如果您看完本篇文章感觉不错,请点击一下右下角的 [推荐] 来支持一下博主,谢谢!原创文章,转载请注明出处!!!
by http://www.cnblogs.com/haoxuebujuan/p/6023546.html
jQuery源码解读第5章---对Callbacks的解读