jq源码学习9_Callbacks : 回调对象 : 对函数的统一管理

基于jquery-2.0.3的源码学习

//9. Callbacks : 回调对象 : 对函数的统一管理
//once: 确保这个回调列表只执行一次(像一个递延 Deferred).
//memory: 保持以前的值和将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred).
//unique: 确保一次只能添加一个回调(所以有没有在列表中的重复).
//stopOnFalse: 当一个回调返回false 时中断调用
var optionsCache = {};//建立json变量缓存
// 工具函数,将字符串格式得标记转换为对象格式得标记。
function createOptions(options){
  // 对象object用于存储转换后的标记对象,其属性为标记字符串,属性值为true。
  var object = optionsCache[options] = {};
  jQuery.each(options.match(core_rnotwhite) ||[],function( _, flag ){
    // 用空白符把标记字符串分割为数组,然后遍历数组,为返回值object,添加单个标记,属性值一律为true
     object[flag] = true;
  });
   // 最后返回对象格式的标记
  return object;
}
//如果 jQuery.Callbacks的参数是 $.Callbacks('one memory')
//则options:{one:true,memory:true}
/*optionsCache:{
  'one memory':{one:true,memory:true}
}*/
 jQuery.Callbacks = function(options){
   // 解析字符串标记options为对象
  // 如果options是字符串,调用工具函数createOptions(options)将标记字符串options解析为标记对象,
  //否则调用jquery.extend()将options中的内容合并到一个空对象中
   //通过字符串在optionsCache寻找有没有相应缓存,如果没有则创建一个,有则引用
   //如果是对象则通过jQuery.extend深复制后赋给options。
   options = typeof options === "string"?
   ( optionsCache[ options ] || createOptions( options ) ) :
   jQuery.extend( {}, options );
   //声明局部变量
   var 
   memory, // 最后一次触发回调时传的参数
   fired,// 列表中的函数是否已经回调至少一次
   firing,//列表中的函数是否正在回调中
   firingStart,// 回调的起点
   firingLength,// 回调时的循环结尾
   firingIndex,// 当前正在回调的函数索引
   list = [], // 回调函数列表
   stack = !options.once && [],// 可重复的回调函数堆栈,用于控制触发回调时的参数列表
   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 ) {
					memory = false; //阻止未来可能由于add所产生的回调
					break;
				}
      }
      firing = false;//标记回调结束
      if ( list ) {
				if ( stack ) {
					if ( stack.length ) {
              //从堆栈头部取出,递归fire
						fire( stack.shift() );
					}
				} else if ( memory ) {//否则,如果有记忆
					list = [];
				} else {//再否则阻止回调列表中的回调
					self.disable();
				}
			}
   },
   self={  // 暴露在外的Callbacks对象,对外接口
      add:function(){ // 回调列表中添加一个回调或回调的集合
        if(list){
          //首先我们存储当前列表长度
           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"){
                   add(arg);
                }
              });
           })(arguments);
           //如果回调列表中的回调正在执行时,其中的一个回调函数执行了Callbacks.add操作
           // 上句话可以简称:如果在执行Callbacks.add操作的状态为firing时
           // 那么需要更新firingLength值
           if(firing){
               firingLength = list.length;
           }else if(memory){
              //如果options.memory为true,则将memory做为参数,应用最近增加的回调函数
              firingStart = start;
              fire( memory );
           }
        }
        //return this就是返回当前对象的引用(就是实际调用这个方法的实例化对象)
        return this;
      },
      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 );
                    if(firing){
                       if(index <= firingLength){
                          firingLength -- ;
                       }
                       if(index <= firingIndex){
                           firingIndex --;
                       }
                    }
                }
           });
        }
        return this;
      },
     has:function(fn){// 回调函数是否在列表中.
         return fn ? jQuery.isArray( fn, list ,index ) > -1 : !!(list && list.length);
     },
     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;
    },
    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;
    },
    fire: function() {// 以给定的参数调用所有回调函数
      self.fireWith( this, arguments );
      return this;
    },
    fired: function() {// 回调函数列表是否至少被调用一次
      return !!fired;
    }
   };
   return self;
 }
//9. Callbacks : 回调对象 : 对函数的统一管理

参考了https://zixuephp.net/manual-javascript-682.html

发布了139 篇原创文章 · 获赞 27 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/chunchun1230/article/details/104190839