jquery Callbacks 回调对象的读书笔记-源码分析

Callbacks:回调对象,函数的一个统一管理(观察者模式)

基本使用

function test1() {
    console.log("test1 ...");
}
function test2() {
    console.log("test2 ...");
}
var cb = $.Callbacks();
cb.add(test1);
cb.add(test2);
cb.fire();

结果:json

test1 ...数组

test2 ...缓存

 

基本用处

1.对不一样做用域的函数进行统一的管理app

2.简化统一调用函数

看下面的例子:this

var cb = $.Callbacks();//声明一个全局的回调对象
function test1() {
    console.log("test1 ...");
}
cb.add(test1);
(function () {
    function test2() {//test2为局部函数,外层中不能调用
        console.log("test2 ...");
    }
    cb.add(test2);
})();
cb.fire()//简化了调用方式

结果:spa

test1 ...对象

test2 ...递归

 

Callbacks(options)参数

参数说明:索引

1.once:使回调函数只能被调用一次,如:

cb.fire();

cb.fire();//第二次调用回调函数将无效

2.memory:无视添加回调函数的顺序,如:

cb.add(test1);

cb.fire();//test1/test2都将会执行

cb.add(test2);

3.unique:去除重复的回调函数,如:

cb.add(test1);

cb.add(test1);

cb.fire();//test1只会调用一次

4.stopOnFalse:当添加的回调函数有返回false时,后续的回调函数将不执行

cb.add(test1);//假设test1()为return false

cb.add(test2);

cb.fire();//将只会执行到test1,test2不会执行

5.此外,Callbacks还支持多个参数共同传递,如Callbacks('memory once')

参数处理:

var optionsCache = {};//options的缓存对象
function createOptions( options ) {
    var object = optionsCache[ options ] = {};
    jQuery.each(//遍历options数组,进行处理
        options.match( core_rnotwhite ) || [],//对options进行空格的切分
        function( _, flag ) {
             object[ flag ] = true;//对单个option进行存放
         }
    );
    return object;
}
options =
    typeof options === "string" ?//判断options是字符串
    ( optionsCache[ options ]//读取缓存options
    || createOptions( options )//建立缓存对象
    ) :
    jQuery.extend( {}, options );//options为空时,合并类数组,防止出现undefined

Callbacks('memory once')

1.options的状况:createOptions( options )返回的是{once:true, memory:true}

2.optionsCache的状况:optionsCache的值为{'once memory':{once:true, memory:true}}

3.options从新赋值:先根据options取optionsCache的值,为空则建立一个options

 

js中的默认的true与false:

1.false状况:false null undefined 0 '' NaN

2.true状况:包括对象、数组、正则、函数等。注意 '0'、'null'、'false'、{}、[]也都是true

3.未定义的变量直接判断true/false程序报错

 

Callbacks的私有成员

私有变量:

1.memeroy:最后一次触发回调时传的参数

2.fired:列表中的函数是否已经回调至少一次

3.firing:列表中的回调函数是否正在被回调中

4.firingStart:回调的起点

5.firingLength:须要fire的队列长度

6.firingIndex:当前正在firing的回调的队列的索引

7.list:[],定义回调函数列表

8.stack:!options.once&&[],当options有once属性时stack为[](主要用来保存当前正在执行回调函数时的函数,),不然为true

私有方法:在这里真正执行须要回调的函数

fire = function( data ) {//data= [context, [arg1, arg2, arg3, ...]],context=this
    memory = options.memory && data;//判断options是否有memory参数,无为undefined,不然为data
    fired = true;
    firingIndex = firingStart || 0;//赋值firingIndex
    firingStart = 0;//初始为0
    firingLength = list.length;//回调列表长度
    firing = true;//true表示回调函数正在执行
    for ( ; list && firingIndex < firingLength; firingIndex++ ) {//遍历回调列表
        // data[ 0 ]是函数执行的上下文,也就是平时的this
        // 这里看再看下 self.fireWith 传过来的参数 args 的格式
        // 若是是stopOnFalse管理器,而且回调返回值是false,中断!
        // list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) 是最终的执行回调的方法
        if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {//options中的stopOnFalse在这做用,执行带有false的回调函数而且有stopOnFalse参数,break出循环
            memory = false; // To prevent further calls using add
            break;
        }
    }
    firing = false;
    if ( list ) {
        if ( stack ) {
            if ( stack.length ) {
                fire( stack.shift() );
            }
        } else if ( memory ) {//options为stopOnFalse和memory的状况
            list = [];
        } else {
            self.disable();
        }
    }
},

 

Callbacks的公有成员

注意:建立Callbacks返回的是self,而self是一个json,存放Callbacks的公有方法

公有方法

1.add

// Actual callback list
list = [],//回调函数列表
add: function() {
    if ( list ) {//list为空是,为ture
        // First, we save the current length
        var start = list.length;//保存回调函数列表的长度
        (function add( args ) {//add自执行函数
            jQuery.each( args, function( _, arg ) {//遍历参数,args=arguments
                var type = jQuery.type( arg );//判断参数的类型
                if ( type === "function" ) {
                    if ( !options.unique || !self.has( arg ) ) {//options中的unique在这做用,判断建立Callbacks是否有unique,取反,后判断回调函数是否在回调列表中
                        //1.options.unique为true,则为false,arg在list为true,反为false,不push进list中,反之
                        //2.options.unique为undefined ,则为true,不判断唯一性,直接push
                        list.push( arg );
                    }
                } else if ( arg && arg.length && type !== "string" ) {//cb.add([test2,test1])这种状况
                    // Inspect recursively
                    add( arg );//进行递归调用
                }
            });
        })( arguments );//将arguments传进add
        // Do we need to add the callbacks to the
        // current firing batch?
        if ( firing ) {//若是当前在 firing 当中,那就把须要firing的长度设置成列表长度
            firingLength = list.length;
            // With memory, if we're not firing then
            // we should call right away
        } else if ( memory ) {//options中的memory在这做用,add后在次调用了fire
            //初始memory为空,则为false,当进行一次fire后,memory判断为true,调用fire,执行回调函数
            firingStart = start;
            fire( memory );
        }
    }
    return this;
},

3.fire():执行回调列表中的回调方法,调用了另外一个公有方法,并传递this和参数列表

fire: function() {//调用回调函数
    self.fireWith( this, arguments );//支持cb.fire('hello');
    return this;
},

4.fireWith():带有参数的调用私有的fire()

// 以给定的上下文和参数调用全部回调函数
fireWith: function( context, args ) {
    if ( list && ( !fired || stack ) ) {//options中的once在这做用,有once时,stack为false,当fire一次后,fired为true,因此第二次fire不执行
        args = args || [];
        args = [ context, args.slice ? args.slice() : args ];  // 把 args 组织成 [context, [arg1, arg2, arg3, ...]]
        // function aaa() {
        //     console.log(111)
        //     cb.fire();
        // }
        // function bbb() {
        //     console.log(222)
        // }
        // var cb = $.Callbacks();
        // cb.add(aaa);
        // cb.add(bbb);
        // cb.fire();这种状况
        if ( firing ) {// 若是当前还在 firing,
            stack.push( args ); // 将参数推入堆栈,等待当前回调结束再调用
        } else {
            fire( args );//args包含this和arguments
        }
    }
    return this;
},

5.empty()

empty: function() {//清空回调列表
    list = [];
    firingLength = 0;
    return this;
},

6.disable()

// 禁用回调列表中的回调
// 禁用掉以后,把里边的队列、栈等所有清空了!没法再恢复了,再次调用fire()无效
disable: function() {
    list = stack = memory = undefined;
    return this;
},

7.disabled():判断是否禁止,当调用disable()后,list为undefined,取反

disabled: function() {
    return !list;
},

8.lock()

lock: function() {//锁住数组,禁止第二次fire(),
    stack = undefined;//清空栈,fire()一次后fired=true,fireWith()中( !fired || stack ) 为false
    if ( !memory ) {
        self.disable();
    }
    return this;
},

9.locked():lock后stack为undefined,取反,当options中有once参数,后续lock操做没意义

locked: function() {//list是否被锁住,返回一个锁标志
    return !stack;
},

10.remove():删除回调列表,支持多个回调函数一块儿删除

remove: function() {//删除回调列表
    if ( list ) {
        jQuery.each( arguments, function( _, arg ) {//遍历参数列表
            var index;
            while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                // splice(index,howmany) 方法向/从数组中添加/删除项目,而后返回被删除的项目
                // index -- 必需。整数,规定添加/删除项目的位置
                // howmany -- 必需。要删除的项目数量。若是设置为 0,则不会删除项目
                // 从回调队列中移除当前查找到的这个方法
                list.splice( index, 1 );
                // Handle firing indexes
                // 在函数列表处于firing状态时,最主要的就是维护firingLength和firgingIndex这两个值
                // 保证fire时函数列表中的函数可以被正确执行,防止取到(fire中的for循环须要这两个值
                // function aaa() {
                //     console.log(1);
                //     cb.remove(bbb);
                // }
                if ( firing ) {
                    if ( index <= firingLength ) {
                        firingLength--;
                    }
                    if ( index <= firingIndex ) {
                        firingIndex--;
                    }
                }
            }
        });
    }
    return this;
},
相关文章
相关标签/搜索