ihtml5 / blog

个人博客 源码阅读*前端实践 My Blog
MIT License
6 stars 0 forks source link

jquery源码阅读之callbacks篇 #59

Open ihtml5 opened 7 years ago

ihtml5 commented 7 years ago

一、callbacks模块作用

callbacks模块通过维护一个回调函数列表,来实现对回调函数地管理。其操作包括增加,触发,移除,清空,禁用,锁定等,是jquery.Defrred, jquery.ajax, jquery.ready等依赖的底层模块。

二、代码示例


let cbList = $.callbacks('once memory');
let fn = (args) => {
    alert(String(args));
}
cbList.add( fn);
cbList.fire('will fire');

三、API 详解

  1. add(fn || fnCollections)

    增加一个或多个回调函数到内部回调函数列表中

  2. fire(args)

    将给定的参数挨个传进回调函数列表中的函数,并执行 回调函数执行的上下文是当前callbacks

  3. fireWith(context, args)

    将给定的参数挨个传进回调函数列表中的函数,并执行 回调函数执行的上下文是当前传入的context

  4. disable

    禁用任何添加和触发操作,删除回调函数列表,清空记忆值,清空参数记忆数组,终止回调函数中所有操作

  5. lock

    禁用callbacks的触发操作 如果当前不是memory模式且回调函数列表并没有在执行,则相当于disable操作 否则,只会禁用触发操作,后续的添加操作不会受影响

  6. remove(fn)

    从回调函数列表中移除fn

  7. empty()

    清空回调函数列表

  8. has(fn)

    判断fn是否在当前回调函数列表中,如果fn为空,则判断当前回调函数列表是否为空

  9. locked()

    判断当前回调函数列表是否处于锁定状态

  10. disabled()

    返回当前回调函数列表的禁用状态

四、源码分析

  1. 整体结构
    /*
    1. 工具函数
    2. 将以空格为分隔的字符串转为对象
    */
    function createOptions(options) {
    }
    let callbacks = function (options) {
    //  获取当前传入的options值
    options = createOptions(options) || {};
    /*
    定义下面函数需要的各种变量
    +. list  回调函数列表
    +. firing 当前回调函数是否在执行
    +. fired  当前回调函数列表是否至少已经执行过一次
    +. locked 当前回调函数列表是否被锁定
    +. disabled 当前回调函数列表是否被禁用
    +. queue 存储回调函数列表触发时传入的参数,是个二维数组,每次传入[context, args]
    +. memory 这个值标示queue的值如何处理,值存在多种情况
       > + options.memory不存在,memory为false
       > + 回调函数执行返回false且存在stopOnFalse标示时
       > + 禁用状态下 memory值为空字符串
       > + 锁定状态下,如果不存在memory标示,且回调函数列表并没有在执行,此时memory为空字符串
      > + 其它情况 memory = [context, args], 用来获取queue中存储的记忆参数
    */
    // 定义一个对象用来存储callbacks的各种方法,如下
    let self = {
      add: function () {},
      fire: function () {},
      fireWith: function () {},
      remove: function () {},
      empty: function () {},
      has: function () {},
      lock: function () {},
      disable: function () {},
      disabled: function () {}
    }
    return self;
    }
  2. 核心工具函数

fire 具体触发过程

(4) lock

    /*
        1.设置locked和queue等于空数组
        2. 这里有个疑问为什么不直接设置locked为true呢,其实空数组就是等于true
        3. 如果memory为false或者为空,且当前回调函数列表尚没有执行,则彻底删除
        回调函数列表, 设置memory等于空字符串。
    */

    locked = queue = [];
    if (!memory && !firing) {
        list = memory = '';
    }
    return this;

(5) disable()

  locked = queue;
  list = memory = '';
  return this;

(6) locked()

return !!locked

(7) disabled()

/*
判断列表是否禁用
*/
return !list

(8) empty()

    // 清空列表
    if (list) {
        list = [];
    }

(9) has(fn)

// 判断函数是否在回调函数列表,如果fn为空,则判断该函数列表是否长度大于0
// $.inArray(data, list, index) 返回某个数据在列表中的位置 类似于indexOf
return fn ? $.inArray(fn, list) > -1 ? list.length > 0;

(10) remove(fn)

    let remove = function (...fns) {
        let index = null;
        // 遍历参数
        $.each(fns, function(_, fn) {
            while (index = ($.inArray(fn, list, index)) > -1 ) {
                list.splice(index, 1);
                if (index <= firingIndex) {
                    firingIndex--;
                } 
            }
        })
    }