zoukankan      html  css  js  c++  java
  • jquery1.8.3 callbacks源码分析

    先附上源码如下

    var optionsCache = {};//缓存options
    
    function createOptions( options ) {  //接受字符串参数,如 传入"unique memory" 
        var object = optionsCache[ options ] = {}; 
        jQuery.each( options.split( core_rspace ), function( _, flag ) {  //按空格分离字符串
            object[ flag ] = true; //optionsCache["unique memory"]["unique"]=true, optionsCache["unique memory"]["memory"]=true
        });
        return object; 
    }
    
    //不管是否传入参数都返回内部的self对象,可以调用对象的add,fire等方法
    jQuery.Callbacks = function( options ) {
        //判断传入参数是否为字符串,是则去optionsCache去获取,没有获取到的话则createOptions创建并返回对象,非字符串,用extend返回对象
        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 = 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; 
                        break;
                    }
                }
                firing = false;
                if ( list ) {
                    if ( stack ) {
                        if ( stack.length ) {
                            fire( stack.shift() );
                        }
                    } else if ( memory ) {
                        list = [];
                    } else {
                        self.disable();
                    }
                }
            },
            self = {
                add: function() {
                    if ( list ) {//判断list是否存在
                        var start = list.length;
                        (function add( args ) {
                            jQuery.each( args, function( _, arg ) {
                                var type = jQuery.type( arg );
                                if ( type === "function" ) {
                                    if ( !options.unique || !self.has( arg ) ) {//如果是unique唯一的,判断list数组是否存在,存在则不push
                                        list.push( arg );//为list添加函数
                                    }
                                } else if ( arg && arg.length && type !== "string" ) {//类数组或数组递归调用,可以看出add接受的为函数列表
                                    add( arg );
                                }
                            });
                        })( arguments );
    
                        if ( firing ) {
                            firingLength = list.length;
                        } else if ( memory ) {
                            firingStart = start;
                            fire( memory );
                        }
                    }
                    return this;
                },
                remove: function() {
                    if ( list ) {
                        jQuery.each( arguments, function( _, arg ) {
                            var index;
                            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 ) {//判断fn是否存在list中
                    return jQuery.inArray( fn, list ) > -1;
                },
                empty: function() {
                    list = [];
                    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 ) {
                    args = args || [];
                    args = [ context, args.slice ? args.slice() : args ];
                    if ( list && ( !fired || stack ) ) {
                        if ( firing ) {
                            stack.push( args );
                        } else {
                            fire( args );
                        }
                    }
                    return this;
                },
                fire: function() {//触发callbacks
                    self.fireWith( this, arguments );
                    return this;
                },
                fired: function() {
                    return !!fired;
                }
            };
    
        return self;
    };

    上面没有全写注释是因为感觉说不清楚,下面按支持的flags分几种情况

    1、直接用的情况

    function f1(v){

    console.log("f1:"+v);

    }

    function f2(v){

    console.log("f2:"+v);

    }

    function f3(v){

    console.log("f3:"+v);

    }

    var cb=$.Callbacks();

    cb.add(f1);

    cb.fire("foo");//f1:foo

    cb.add(f2,f3);

    cb.fire("bar");//f1:bar f2:bar  f3:bar 

    cb.fire("bar2");//f1:bar2 f2:bar2  f3:bar2 

    可以看出cb可以add在add,fire在fire

    跟进源码分析

    cb.add中把函数push进list数组,firing,memory都为false不用管,add操作ok

    cb.fire调用了fireWith,可以看出fireWith可以自己绑定context,fire则默认为this

    fireWith: function( context, args ) {
    args = args || [];
    args = [ context, args.slice ? args.slice() : args ];
    if ( list && ( !fired || stack ) ) { //!fired和stack均为true
      if ( firing ) { //firing为false
        stack.push( args );
      } else {
        fire( args );
      }
    }
    return this;
    }

    可以看出调用了Callbacks内部的fire函数,里面循环调用list里的函数,firingIndex一直为0,所以再次add或调用,里面的list函数都重新执行一遍,接着

    if ( list ) {
    if ( stack ) {//这里为true
    if ( stack.length ) {//为false,所以什么都不做,cb.fire操作也ok结束
    fire( stack.shift() );
    }
    } else if ( memory ) {
    list = [];
    } else {
    self.disable();
    }
    }

    2传入once的情况

    var cb=$.Callbacks(“once”);

    cb.add(f1);

    cb.fire("foo");//f1:foo

    cb.add(f2,f3);

    cb.fire("bar");//无

    cb.fire("bar2");//无

    cb.add同上

    cb.fire基本同上,只不过这里不同

    if ( list ) {
    if ( stack ) {//为false
    if ( stack.length ) {
    fire( stack.shift() );
    }
    } else if ( memory ) {
    list = [];
    } else {
    self.disable();//走到了这里 list = stack = memory = undefined;都设置了undefined,当你在add或fire的时候,list为undefined,所以不做任何操作
    }
    }

    3传入memory的情况

    var cb=$.Callbacks(“memory”);

    cb.add(f1);

    cb.fire("foo");//f1:foo

    cb.add(f2,f3);//f2:foo f3:foo

    cb.fire("bar")//f1:bar f2:bar f3:bar

    这里与第一种情况基本相同,

    if ( firing ) {
    firingLength = list.length;
    } else if ( memory ) {//只不过在第一次以后的add的时候,走这里
    firingStart = start;//这里改变长度,为只给新添加的函数执行
    fire( memory );//在add的时候把上次fire的数据传给此次add的函数执行
    }

    3传入unique的情况

    这个比较简单,在add的时候判断添加的函数是否已经存在

    if ( !options.unique || !self.has( arg ) ) {//如果是unique唯一的,判断list数组是否存在,存在则不push
    list.push( arg );//为list添加函数
    }

    4传入stopOnFalse的情况

    if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {//可以看到就这里有stopOnFalse 这种情况就break了
    memory = false; 
    break;
    }

    5传入多个的情况

    1)"unique memory"这种情况就是添加的重复的不执行

    2)"memory stopOnFalse "

    function f1(v){

    console.log("f1:"+v);
    return false

    }

    function f2(v){

    console.log("f2:"+v);

    }

    function f3(v){

    console.log("f3:"+v);

    }

    var cb=$.Callbacks("memory stopOnFalse");

    cb.add(f1);

    cb.fire("foo");//f1:foo

    cb.add(f2,f3);//无

    if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {//可以看到就这里有stopOnFalse 这种情况就break了
    memory = false; 可以看到这里memory =false
    break;
    }

    所以add的时候

    if ( firing ) {
    firingLength = list.length;
    } else if ( memory ) {//不走这里
    firingStart = start;
    fire( memory );//不执行
    }

    3)"memory once"

    var cb=$.Callbacks("memory once");

    cb.add(f1);

    cb.fire("foo");//f1:foo

    cb.add(f2,f3);//f2:foo f3:foo

    cb.fire("bar")//无

    在第一次fire时,

    if ( list ) {
    if ( stack ) {
    if ( stack.length ) {
    fire( stack.shift() );
    }
    } else if ( memory ) {//走了这里,list重置
    list = [];
    } else {
    self.disable();
    }
    }
    在下一次add时,
    if ( firing ) {
    firingLength = list.length;
    // With memory, if we're not firing then
    // we should call right away
    } else if ( memory ) {//走了这里,所以新添加的直接传入上次的值执行
    firingStart = start;
    fire( memory );
    }
    当你在fire时,list为[]所以什么都不执行,再次充值list=[]

    6执行的时候在add或fire的情况

    function f1(v){

    console.log("f1:"+v);
    cb.add(f3)

    }

    function f2(v){

    console.log("f2:"+v);

    }

    function f3(v){

    console.log("f3:"+v);

    }

    var cb=$.Callbacks("memory");

    cb.add(f1);

    cb.fire("foo");//f1:foo f3:foo

    cb.add(f2);//f2:foo

    你可以发现当f1执行时又cb.add了

    if ( firing ) {//这时firing为true
    firingLength = list.length;//加长到当前list数组长度,以便执行新添加的
    } else if ( memory ) {
    firingStart = start;
    fire( memory );
    }

    至于其他组合和情况以及empty、remove、lock方法我想你能分析了...good job...

  • 相关阅读:
    Sum Root to Leaf Numbers 解答
    459. Repeated Substring Pattern
    71. Simplify Path
    89. Gray Code
    73. Set Matrix Zeroes
    297. Serialize and Deserialize Binary Tree
    449. Serialize and Deserialize BST
    451. Sort Characters By Frequency
    165. Compare Version Numbers
    447. Number of Boomerangs
  • 原文地址:https://www.cnblogs.com/ygm125/p/2800788.html
Copyright © 2011-2022 走看看