jQuery的callback函数

基本使用

  • 如果不传入参数flags,则回调函数列表的行为类似于事件监听函数,能够被触发多次
    在这里插入图片描述
// 基本使用
function aaa(){
  alert(1);
}

function bbb(){
  alert(2);
}

var cb = $.Callbacks();
cb.add(aaa);
cb.add(bbb);

cb.fire();

//-------------------------------

var cb = $.Callbacks();

function aaa(){
  alert(1);
}

cd.add(aaa);

(function(){
  function bbb(){
    alert(2);
  }
  cb.add(bbb);
})

cd.fire();

//-----------------------------------
// 四个参数的作用
// once: fire() 只能触发一次
var cb = $.Callbacks('once');
// memory: 只要写入Callbacks里面的,不管先后顺序,都可以触发
var cb = $.Callbacks('memory');
cb.add(aaa);
db.fire();
cb.add(bbb);
// unique: 不会重复触发相同的函数
// stopOnFalse
function aaa(){
  alert(1);
  return false;   // 会终止,以后的不会触发
}

function bbb(){
  alert(2);
}

function ccc(){
  alert(3)
}

var cb = $.Callbacks('stopOnFalse');

cb.add(aaa);
cb.add(bbb);

cd.fire();

// 组合使用
var cb = $.Callbacks('stopOnFalse once');

代码

// String to Object options format cache
// {"once": true, "memory": true}
var optionsCache = {};
  
// Convert String-formatted options into Object-formatted ones and store in cache
function createOptions( options ) {
  // 变量object和flagsCache[ flags ]指向了同一个空对象,object改变的时候,optionsCatche也会改变
  var object = optionsCache[ options ] = {};
  // core_rnotwhite = /\S+/g,
  // console.log("111 222 333".match(/\S+/g));
  // ["111", "222", "333"]
  jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
    // {"once": true, "memory": true}
    object[ flag ] = true;
  });
  return object;
}
/**
 * 四个参数的作用:
 * 1. once :fire() 只能触发一次
 * 2. memory :只要写入Callbacks里面的,不管先后顺序,都可以触发
 * 3. unique :不会重复触发相同的函数
 * 4. stopOnFalse :某个回调函数返回false之后中断后面的回调函数
 */
jQuery.Callbacks = function( options ) {
  
  // Convert options from String-formatted to Object-formatted if needed
  // (we check in cache first)
  // options 可以传入一个字符串或一个对象
  // {"test": "true", "one": "true", "two": "true", "three": "true"}
  // 先尝试从缓存对象flagsCache中获取标记字符串flags对应的标记对象,如果没有找到,再调用工具函数createFlags(flags)将标记字符串flags解析为标记对象,并放入缓存对象flagsCache中
  options = typeof options === "string" ?
    ( optionsCache[ options ] || createOptions( options ) ) :
    // jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。如果目标对象有相同属性,后面的覆盖前面的
    jQuery.extend( {}, options );

  var // Last fire value (for non-forgettable lists)
    // 最近一次触发回调的参数
    // 变量memory的初始值为undefined,表示当前回调函数列表未被触发过
    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
    // 可重复的回调函数堆栈,用于控制触发回调时的参数列表
    // once的作用在这里体现(once:只能触发一次)
    // stack = false
    stack = !options.once && [],

    /**
     * 我终于看懂啥意思了,首先看add函数,看完了吧,之后咱看fire函数
     */
    // Fire callbacks
    // 触发回调函数列表
    // fire(context,args),参数context用于指定回调函数执行时的上下文,即关键字this所引用的对象,参数args用于指定调用回调函数时传入的参数
    fire = function( data ) {
      memory = options.memory && data;
      // 是否回调列表已经执行过至少一次
      fired = true;
      firingIndex = firingStart || 0;
      firingStart = 0;
      firingLength = list.length;
      // 回调列表是否在执行中
      firing = true;
      for ( ; list && firingIndex < firingLength; firingIndex++ ) {
        // 有关stopOnFalse的代码
        // db.fire();   /   db.fire(context, "XXX") 可以传参数,也可以不传参数
        // 如果执行这个函数的返回值是false,且user需要stopOnFalse,就终止循环
        // 且如果有memory,也改为false
        if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
          memory = false; // To prevent further calls using add
          break;
        }
      }
      firing = false;
      // 如果list里面有内容,说明是刚才存下来的,得把里面的参数都执行了
      // 为什么不用while循环执行stack里面的内容,因为是递归,下次还会检查list里面是否有内容
      if ( list ) {
        if ( stack ) {
          // stack = !options.once && [],
          if ( stack.length ) {
            // shift () 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
            // 删除,说明这个已经执行过了,之后不用再执行了
            fire( stack.shift() );
          }
          // once + memory 模式
          // 则清空数组list,后续添加的回调函数还会立即执行
        } else if ( memory ) {
          list = [];
        } else {
          self.disable();
        }
      }
    },
    // self是最后返回的对象
    // 添加一个或多个回调函数到数组list中。如果是unique模式,并且待添加的回调函数已添加过,则不会添加。该函数通过闭包机制引用数组list
    self = {
      // Add a callback or a collection of callbacks to the list
      // 方法callbacks.add()用于添加一个或一组回调函数到回调函数列表中,通过调用工具函数add(args)实现;在memory模式下,如果回调函数列表未在执行中,并且已经被触发过,则立即执行新添加的回调函数。
      add: function() {
        // 如果list存在
        if ( list ) {
          // 从list的末尾开始添加
          var start = list.length;
          // 匿名函数自执行 add the function to list
          // cb.add(aaa, bbb);
          // 把回调函数逐个添加到数组list中。添加时检查args[i]的类型,如果args[i]是数组,则迭代调用工具函数add(args)把数组中的回调函数添加到数组list中;如果args[i]是函数并且不是unique模式,或者是unique模式但未添加过,才会添加args[i]到数组list中。函数以外的类型,则被忽略。
          (function add( args ) {
            jQuery.each( args, function( _, arg ) {
              var type = jQuery.type( arg );
              if ( type === "function" ) {
                // if options.unique == true, this is said user need unique
                // so have to check list has arg or not
                if ( !options.unique || !self.has( arg ) ) {
                  list.push( arg );
                }
              // arg is function or sameFunction ([] or {0: , 1: , 2: , length: 3})
              // cb.add([aaa, bbb], ccc);
              } else if ( arg && arg.length && type !== "string" ) {
                // 递归调用
                add( arg );
              }
            });
          })( arguments );
          // Do we need to add the callbacks to the
          // current firing batch?
          // 如果正在fire list里面的内容
          // 改变firingLength的长度
          // 修正结束下标firingLength,使得新添加的回调函数也得以执行。
          if ( firing ) {
            firingLength = list.length;
          // With memory, if we're not firing then
          // we should call right away
          // 如果在调用这个函数之前,设置了memory状态,直接将这个函数之后所有函数fire一遍
          } else if ( memory ) {
            firingStart = start;
            fire( memory );
          }
        }
        return this;
      },
      // Remove a callback from the list
      // cb.remove(aaa, bbb);
      remove: function() {
        if ( list ) {
          jQuery.each( arguments, function( _, arg ) {
            var index;
            // 万一有多个,所以用while
            while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
              list.splice( index, 1 );
              // Handle firing indexes
              // 则会修正结束下标firingLength和当前下标firingIndex,确保移除的同时不会遗漏执行回调函数。
              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.
      // 如果!!( list && list.length )成立,fn为null undefined 都返回true
      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状态,返回true或false
      disabled: function() {
        return !list;
      },
      // Lock the list in its current state
      // 回调列被锁死,再调用callbacks.fire()或callbacks.fireWith()都将失效
      // callbacks有memory标记:当前fire()或fireWith()方法中没有执行的回调会继续执行,但回调中的callbacks.fire()和callbacks.fireWith()都不会再起作用。
	  // callbacks无memory标记:所有回调全部被清空,也就是说后面的回调都不再执行。
      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
      // 使用指定的上下文context和参数args调用数组list中的回调函数。该函数通过闭包机制引用数组list
      // 在memory模式下,回调函数列表的方法callbacks.add()在添加回调函数后,如果回调函数列表未禁用并且已经被触发过,也会调用工具函数fire(context,args)来立即执行新添加的回调函数。
      fireWith: function( context, args ) {
        // fired是是否至少执行过一次,如果没执行过,是false,可以执行下面的内容
        // 如果之前执行过,再看看stack是否存在,如果stack存在,也可以执行下面的内容
        if ( list && ( !fired || stack ) ) {
          args = args || [];
          args = [ context, args.slice ? args.slice() : args ];
          if ( firing ) {
            // 如果执行函数的时候,不需要参数,args就是[]
            // 如果执行函数的时候,需要函数,args里面就是有内容的
            // stack表示需要执行几次list里面的内容,并附带有context和args
            // 如果list正在firing,将args放入stack,之后再执行
            stack.push( args );
          } else {
            // 如果list不在firing,直接执行
            fire( args );
          }
        }
        return this;
      },
      // Call all the callbacks with the given arguments
      fire: function() {
        // this是context,arguments是cb.fire()里面带的参数,意思就是执行list函数的时候,函数都可以带着arguments里面的参数
        self.fireWith( this, arguments );
        return this;
      },
      // To know if the callbacks have already been called at least once
      fired: function() {
        return !!fired;
      }
    };

  return self;
};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值