澳门新莆京手机网站-新蒲京娱乐场 > 计算机 > 新蒲京娱乐场:jQuery源码深入分析之Callbacks精解_jquery_脚本之家

新蒲京娱乐场:jQuery源码深入分析之Callbacks精解_jquery_脚本之家

javascript具备函数式编制程序的特点,而又因为javascript单线程蒸蒸气机,我们的函数总是须求有序的试行。卓越代码平时把函数切割成各自的模块,然后在某后生可畏特定条件下实践,既然这个函数是一动不动的执行,那么我们为啥不编写一个联合保管的指标,来扶助大家管理那一个函数——于是,Callbacks诞生。

    var // Flag to know if list is currently firing
        firing,
        // Last fire value (for non-forgettable lists)
        memory,
        // Flag to know if list was already fired
        fired,
        // End of the loop when firing
        firingLength,
        // Index of currently firing callback (modified by remove if needed)
        firingIndex,
        // First callback to fire (used internally by add and fireWith)
        firingStart,
        // Actual callback list
        list = [],
        // Stack of fire calls for repeatable lists
        stack = !options.once && [],
        // Fire callbacks
        // data传递的是七个数组
        // 使用Callbacks.fireWidth时,data富含fireWith函数字传送递的一个上下文意况和三个数组
        // 使用Callbacks.fire时,data包含Callbacks对象和fire函数的arguments对象
        fire = function( data ) {
            // 如果options.memory为true,记录下data传递的数组
            memory = options.memory && data;
            fired = true;
            // 要是options.memory为true,firingStart为上一次Callbacks.add后回调列表的length值
            firingIndex = firingStart || 0;
            // 重置firingStart为0
            firingStart = 0;
            firingLength = list.length;
            firing = true;
            for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                // 将data作为参数,试行回调列表中的全部回调
                // 如若回调列表中内部二个回调重临false,且options.stopOnFalse为true,则中断接下去别的回调的执行
                // 假使options.memory为true,将memory设置为false,阻止在Callbacks.add中新扩充回调的施行
                if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
                    memory = false; // To prevent further calls using add
                    break;
                }
            }
            firing = false;
            if ( list ) {
                // 如果options.once为false
                if ( stack ) {
                    // stack在fireWith操作时也许全体成员
                    // 当stack具有成员时(唯有三个卡塔尔国,并将其成员作为参数字传送递给将在推行的兼具回调
                    if ( stack.length ) {
                        fire( stack.shift() );
                    }
                }
                // 假如options.memory为true且options.once为true,那么在add中推行一次fire(只进行最新扩展加的回调卡塔尔(قطر‎
                // 这里安装list = [],那么再一次fire时,将不会有任何操作
                else if ( memory ) {
                    list = [];
                }
                // 假使存在options.once为true,options.memory为false的别样情状,将禁止使用Callbacks对象
                else {
                    self.disable();
                }
            }
        },
        // Actual Callbacks object
        self = {
            // Add a callback or a collection of callbacks to the list
            add: function() {
                if ( list ) {
                    // First, we save the current length
                    var start = list.length;
                    (function add( args ) {
                        jQuery.each( args, function( _, arg ) {
                            var type = jQuery.type( arg );
                            // 如若arg是叁个函数
                            if ( type === "function" ) {
                                // arg为要新添到回调列表中的回调
                                // 如若arg不设有回调列表中,则将它增到回调列表中
                                // 假若arg存在回调列表中,且options.unique为false,则将它增至回调列表中
                                // 假诺arg存在回调列表中,且options.unique为true,则不实践push动作
                                if ( !options.unique || !self.has( arg ) ) {
                                    list.push( arg );
                                }
                            }
                            // 假设arg为数组或伪数组,则递归检查
                            else if ( arg && arg.length && type !== "string" ) {
                                // Inspect recursively
                                add( arg );
                            }
                        });
                    })( arguments );
                    // Do we need to add the callbacks to the
                    // current firing batch?
                    // 借使回调列表中的回调正在推行时,此中的五个回调函数施行了Callbacks.add操作
                    // 上句话能够简单的称呼:如果在试行Callbacks.add操作的情事为firing时
                    // 那么须求更新firingLength值
                    if ( firing ) {
                        firingLength = list.length;
                    // With memory, if we're not firing then
                    // we should call right away
                    // 假使options.memory为true,则将memory做为参数,应用这段日子追加的回调函数
                    } else if ( memory ) {
                        firingStart = start;
                        fire( memory );
                    }
                }
                return this;
            },
            // Remove a callback from the list
            remove: function() {
                if ( list ) {
                    jQuery.each( arguments, function( _, arg ) {
                        var index;
                        // 通过找到arguments成员在回调列表中索引地方遍历arguments对象,并将arguments成员从回调列表中移除
                        while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                            list.splice( index, 1 );
                            // Handle firing indexes
                            // 借使在执行Callbacks.remove操作的状态为firing时
                            // 则更新firingLength和firingIndex的值
                            if ( firing ) {
                                if ( index <= firingLength ) {
                                    firingLength--;
                                }
                                // 特殊管理,假若移除的回调的目录小于当前正值实施回调的目录,则firingIdex--
                                // 前面未进行的回调则能够平常实行
                                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.
            // 检查fn是或不是留存回调列表中
            has: function( fn ) {
                return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
            },
            // Remove all callbacks from the list
            // 清空回调列表中的全部回调
            empty: function() {
                list = [];
                return this;
            },
            // Have the list do nothing anymore
            // 禁用Callbacks对象
            disable: function() {
                list = stack = memory = undefined;
                return this;
            },
            // Is it disabled?
            // 检查回调列表是还是不是被剥夺
            disabled: function() {
                return !list;
            },
            // Lock the list in its current state
            // 锁定回调对象,阻止回调列表中的全数回调的实行
            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
            fireWith: function( context, args ) {
                args = args || [];
                args = [ context, args.slice ? args.slice() : args ];
                if ( list && ( !fired || stack ) ) {
                    // 假使fired为true,options.once为false,且生龙活虎旦在实施fireWith操作的景况为firing
                    // 则将拍卖过的args作为stack数组的首先个数组项,并在firing为false后,将stack第一个数组项作为参数字传送递给将要实行的有所回调
                   
                    // 尽管fired为true,options.once为true,则不进行此外操作
                    // 能够见到,$.Callbacks('once'卡塔尔国表示回调对象只fire贰次
                    if ( firing ) {
                        stack.push( args );
                    }
                    // 第贰遍实行fireWith时,一定实行else分支
                    else {
                        fire( args );
                    }
                }
                return this;
            },
            // Call all the callbacks with the given arguments
            // 将Callbacks对象,及Callbacks.fire函数中的arguments对象传递给Callbacks.fireWith函数,并施行
            fire: function() {
                self.fireWith( this, arguments );
                return this;
            },
            // To know if the callbacks have already been called at least once
            // 是或不是进行过fire函数
            fired: function() {
                return !!fired;
            }
        };
   
    //返回Callbacks对象
    return self;
};

1、全体调用逻辑

self的fire调用self的fireWith,fireWith把参数字传送递到fire(State of Qatar函数。

// Call all callbacks with the given context and arguments
            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;
            },
            // Call all the callbacks with the given arguments
            fire: function() {
                self.fireWith( this, arguments );
                return this;
            },

fire(State of Qatar时根本是for循环

 // Fire callbacks
        fire = function( data ) {
            memory = options.memory && data;
            fired = true;//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 ) {//每次函数调用同时处理stopOnFalse的情况
                    memory = false; // To prevent further calls using add //stopOnFalse后有memory也不好使了
                    break;
                }
            }
            firing = false;//触发结束
            if ( list ) {
                if ( stack ) {
                    if ( stack.length ) {
                        fire( stack.shift() );
                    }
                } else if ( memory ) {
                    list = [];
                } else {
                    self.disable();
                }
            }
        },

实行这么些Callbacks中的函数:我们做的那整个,不都以为了这一刻推行的宿命么?参数将会造成那么些须求施行的函数的参数。fireWith

    // Convert options from String-formatted to Object-formatted if needed
    // (we check in cache first)
    options = typeof options === "string" ?
        // 独有当实施$.Callbacks(参数相似卡塔尔二回及以上时,才不会实践createOptions函数
        ( optionsCache[ options ] || createOptions( options ) ) :
        // 表达也得以这么$.Callbacks({once:true, memory:true}卡塔尔国使用
        jQuery.extend( {}, options );

1、callback4个参数的成效

  • once: 只能够接触三次。
  • memory: 当队列已经接触之后,再增加进去的函数就能够一贯被调用,不须要再触发三遍。
  • unique: 保障函数的天下无双
  • stopOnFalse: 只要有二个回调重临 false,就搁浅后续的调用。

举例:

不传参数,fire三回就接触五次。

新蒲京娱乐场 1function aaa() { alert(1); } function bbb() { alert(2); } var cb = $.Callbacks(); cb.add(aaa); cb.add(bbb); cb.fire(); //1 2 cb.fire();//1 2 View Code

  • once:fire只好触发壹回,源码中fire后假诺有once就把list干掉了,list=undefined了。
        function aaa() {
            alert(1);
        }

        function bbb() {
            alert(2);
        }
        var cb = $.Callbacks('once');
        cb.add(aaa);
        cb.add(bbb);
        cb.fire(); //1 2
        cb.fire();

不传参数,在fire之后add的回调不可能被fire。

新蒲京娱乐场 2//不写参数,只弹出1,2不会弹出 function aaa(卡塔尔(قطر‎ { alert(1State of Qatar; } function bbb(卡塔尔(قطر‎ { alert(2卡塔尔(قطر‎; } var cb = $.Callbacks(State of Qatar; cb.add(aaaState of Qatar; cb.fire(State of Qatar; //1 cb.add(bbbState of Qatar; View Code

  • memory回忆,在fire前面前边add的办法都能赢得奉行。
function aaa() {
            alert(1);
        }

        function bbb() {
            alert(2);
        }
        var cb = $.Callbacks('memory');
        cb.add(aaa);
        cb.fire(); //1 2
        cb.add(bbb);
  • unique:去重

新蒲京娱乐场 3//不加参数,add2次aaa,就能够触发2次aaa function aaa(卡塔尔(قطر‎ { alert(1卡塔尔; } var cb = $.Callbacks(卡塔尔(قطر‎; cb.add(aaa卡塔尔; cb.add(aaa卡塔尔国; cb.fire(卡塔尔国; //1 1 View Code

function aaa() {
            alert(1);
        }


        var cb = $.Callbacks('unique');
        cb.add(aaa);
        cb.add(aaa);
        cb.fire(); //1 加了unique参数,同样的函数不能多次add
  • stopOnFalse:函数再次回到false跳出循环
function aaa() {
            alert(1);
            return false;
        }
        function bbb() {
            alert(2);
        }

        var cb = $.Callbacks();
        cb.add(aaa);
        cb.add(bbb);
        cb.fire(); //1 2 不传参,第一个函数返回false时后面的函数也能正常执行

function aaa() {
            alert(1);
            return false;
        }
        function bbb() {
            alert(2);
        }

        var cb = $.Callbacks('stopOnFalse');
        cb.add(aaa);
        cb.add(bbb);
        cb.fire(); //1
        //传参stopOnFalse,第一个函数返回false时后面的函数不再执行

锁定这些Callbacks对象:你恐慌它并不平静,不过你又不想舍弃它,lock是个不利的章程,它接纳二个Boolean的参数,表示是不是须要锁定那个目的,当然,无参的它用来令你规定Callbacks是不是被锁定。fire

/*
 * Create a callback list using the following parameters:
 *
 *    options: an optional list of space-separated options that will change how
 *            the callback list behaves or a more traditional option object
 *
 * By default a callback list will act like an event callback list and can be
 * "fired" multiple times.
 *
 * Possible options:
 *
 *    once:          确认保证回调列表仅只fire贰回
                     will ensure the callback list can only be fired once (like a Deferred)
 *
 *    memory:        在进行过fire后,保存在此以前fire时的参数,该参数会传送给在add中实行的风尚加多的回调
                     will keep track of previous values and will call any callback added
 *                    after the list has been fired right away with the latest "memorized"
 *                    values (like a Deferred)
 *
 *    unique:        确定保证在add操作中,阻止存在回调列表中的回调再度被增加到回调列表中
                     will ensure a callback can only be added once (no duplicate in the list)
 *
 *    stopOnFalse:   当正在实行的回调再次回到false,将中止其余未试行回调的施行
                     interrupt callings when a callback returns false
 *
 */

6、 lock和disable的区别

disable禁绝全数操作

 function aaa() {
            alert(1);
        }
        function bbb() {
            alert(2);
        }

        var cb = $.Callbacks('memory');
        cb.add(aaa);
        cb.fire(); //1
        cb.disable();//disable()后只能弹出1 因为禁止所有操作了,虽然有Memory
        cb.add(bbb);//不起作用了,此时list变为undefined了
        cb.fire();//不起作用了

lock只是锁住数组

function aaa() {
            alert(1);
        }
        function bbb() {
            alert(2);
        }

        var cb = $.Callbacks('memory');
        cb.add(aaa);
        cb.fire(); //1 2
        cb.lock();//lock()只是把后续的fire()锁住,其他操作是锁不住的
        cb.add(bbb);
        cb.fire();//不起作用了 此时list为[]

 

 

参考:

本文我starof,因知识自身在调换,作者也在每每学习成长,文章内容也波动时更新,为防止错误的指导读者,方便追本溯源,请各位转发申明出处:

Callback,jquery源码callback 工具方法。对函数的集结管理。 jquery2.0.3本子$.Callback(卡塔尔国部分的源码如下: // String to Object options format cac...

实行Callbacks中的函数,并且内定上下文。在fire都以Callbacks对象,而fireWidth(卡塔尔国,能够令你再次定义那些要推行的函数的上下文,多么自由的编制程序啊,Callbacks为你着想了全部。fired(State of Qatar

判别那些Callbacks过去是或不是已经进行过:大家相信,相当多时候你并不知道过去做过什么,不过大家记录了你做的整套,借使您过去早就进行过这些Callbacks对象,那么你绝不否认,因为我们明白过去你是不是实践了那么些Callbacks。

核心模块落成

大约的贯彻:我们先来简单的完毕二个Callbacks:

复制代码 代码如下:(function { var Callbacks = function (卡塔尔国 { //通过闭包珍爱这几个个人变量 var list = [],//回调函数列表 fired;//是或不是实施过 //再次回到一个闭包的Callbakcs对象 return { add: function { //当Callbacks放弃掉的时候,list为undefined if { //加多一个回调函数 list.push; //扶植链式回调 } return this; }, fireWith: function { //触发回调函数,并点名上下文 if { fired = true; for (var i = 0, len = list.length; i < len; i++卡塔尔国 { //当Callbacks中某一个函数重返false的时候,甘休Callbacks后续的实行 if (list[i].apply === falseState of Qatar break; } } return this; }, fire: function (){ //触发回调函数 //调用fireWith并钦命上下文 return this.fireWith; }, empty: function (卡塔尔 { //清空list就能够 if //当这几个Callbacks抛弃掉的时候,Callbacks不应有能够世袭行使 list = []; return this; }, disable: function (卡塔尔(قطر‎ { //屏弃这些Callbacks对象,后续的回调函数列表不再试行 list = undefined; return this; }, disabled: function (卡塔尔(قطر‎ {//检查实验这么些Callbacks是不是早已废掉 //转变为boolean再次回到 return !list; }, fired: function (卡塔尔(قطر‎{//那么些callbacks是或不是实践过 return !!fired; } }; }; //注册到window下 window.Callbacks = Callbacks; };

下一场我们测量检验一下以此Callbacks:

复制代码 代码如下: var test = new Callbacks(卡塔尔国; test.add { console.log('函数1,value是:' + value卡塔尔; }卡塔尔(قطر‎; test.add { console.log('函数2,value是:' + value卡塔尔国; }卡塔尔国; test.fire; console.log('查看函数是不是执行过:' + test.fired;//抛弃这么些Callbacks console.log('查看函数是还是不是被甩掉:' + test.disabled; test.add { console.log; }卡塔尔(قطر‎; test.fire(State of Qatar;

展开浏览器的调节台我们得以见到运转结果正常。

once和auto实现

once:once让这几个callbacks中的函数运转一回现在就不再运转。原理非常的简约,上边的代码中,大家可以瞥见有叁个变量list承袭函数列表,所以大家只要求把过去试行过的代码清空就能够。我们用三个全局变量,保存当前实践模型,假设是once模型,就在fireWith(卡塔尔(قطر‎里让这些list失效就能够:

复制代码 代码如下:(function { var Callbacks = function { //通过闭包爱惜那个个人变量 var list = [],//回调函数列表 fired;//是还是不是进行过 //重临贰个闭包的Callbakcs对象 return { //...省略有个别代码 fireWith: function { //触发回调函数,并内定上下文 if { fired = true; for (var i = 0, len = list.length; i < len; i++State of Qatar { //当Callbacks中某二个函数重回false的时候,停止Callbacks后续的实践 if (list[i].apply === false卡塔尔(قطر‎ break; } } //要是配置了once模型,则全局变量once为true,则list重新载入参数 if list = undefined; return this; } //...省略有个别代码 }; }; //注册到window下 window.Callbacks = Callbacks; };

auto模型在jQuery中是以memory命名的,最早被那些命名给混淆了,留意看了用法才分明改成auto——它的作用正是“第二回fire的函数自动施行”,以下处境能够用到:当增多大器晚成组函数到Callbacks之后,有时又需求扩充叁个函数,那么即时运营这一个新添的函数——一定要说,为了利用的造福,那几个形式变得多少为难知晓。达成起来正是在add(卡塔尔国的时等候法庭判果断是还是不是是auto模型,若是是auto模型,则试行那几个函数。 不过,大家必要在首先次fire过的Callbacks并不应当被电动实践,并且,每一遍活动推行后,还须求把最后壹遍使用的参数字传送递传递给那几个活动执行的函数。

也许我们会想到如下代码:

复制代码 代码如下:(function { var Callbacks = function { var list = [], fired, lastData;//保存最后叁次进行的参数 return { add: function { list.push; // — 自动施行格局 //最终一回选择的参数字传送递过去,这里错过了Context //为了不让这里错过上下文,我们大概还索要声Bellamy(Bellamy卡塔尔(قطر‎(DumexState of Qatar个变量保存最后一回利用的Context if this.fire; } return this; }, fireWith: function { if { lastData = data;// — 记录最后三遍采取的参数 fired = true; for (var i = 0, len = list.length; i < len; i++卡塔尔 { if (list[i].apply === false) break; } } if list = []; return this; } //部分代码省略 }; }; //注册到window下 window.Callbacks = Callbacks; };

唯独在jQuery里选拔了更奇异的用法,获取jQuery作者也自豪这种用法,所以命名那么些模型为memory——正是让地点的变量auto不仅意味着如今是auto实行情势,何况作为最终三遍参数的器皿,它既象征了auto,也意味着了memory。(上边包车型大巴代码非jQuery是借助jQuery代码思路而写,非源码):

复制代码 代码如下:(function { var Callbacks = function { var list = [], fired, memory,//主角在这里边,正是memory coreFire = function { //真正的触发函数主意 if { //&&表明式妙用 memory = auto && data;//记录最终一遍的参数,如若不是auto情势则不会记录那个参数 //假设是auto情势,那么这一个auto将不会为false,它会是一个数组 fired = true; for (var i = 0, len = list.length; i < len; i++State of Qatar { if (list[i].apply === false卡塔尔国 break; } } }; return { add: function { //增多三个回调函数 list.push; //自动实行格局,注意如若auto模型 //memory是在coreFire(卡塔尔里赋值的,私下认可是false if coreFire; } //支持链式回调 return this; }, fireWith: function { if list = []; //这里调用coreFire,把参数转变为数组了 coreFire; return this; } /*局部代码省略*/ }; }; window.Callbacks = Callbacks; };

咱俩在上叁个auto实现的代码中来看大家错过了Context,jQuery早在fireWith(卡塔尔中期维修复了那个bug——在fireWith(State of Qatar中期维修复参数。jQuery把fireWith(卡塔尔国中自然应该实行函数的逻辑给分离出来,我们不经常将它命名叫coreFire中,将参数拼接成一个数组:第二个参数表示上下文,第贰个参数表示传递步向的参数。然后实行coreFire的时候,jQuery并未给变量auto赋值,而是精选在coreFire赋值,那样就有限支持了第1回fire(卡塔尔之后才会张开自动实施。

依照地方所说,coreFire(State of Qatar选择的参数其实是一个数组,第多个参数是上下文,第三个参数是外面传递步入的参数。同有的时候间把那些数组赋值给auto,那样,变量auto的定义就成为了memory。真是一语双关的神思路,神主见,一定要打call。作者定义那几个为auto是因为它的本身正是一个活动施行的模子,顺便保存了最后二回fire(State of Qatar的参数,而jQuery定义为memory或然也是小编惊讶这里的独具匠心吧。

有关once&auto就是把那五个代码揉合到生龙活虎道而已,只必要在coreFire(卡塔尔国里剖断假如是auto形式,那么就把list重新苏醒设置为叁个新的数组,不然间接设置为undefined就可以。

源码

那份代码是团结对应jQuery手写的生机勃勃份,将部分jQuery公有的函数都写了进去,并不是代码片段,所以能够直接引用运转。

复制代码 代码如下:(function { /* * 四个回调函数工具对象,注意这一个专门的学问目的专门的职业成功以往就能清空数组: * 提供风华正茂组平时的API,但它犹如下职业模型 - * once - 单次实践模型:每便职业一遍,后续不再职业 * auto - 自动履行模型:每增多二个回调函数,自动实施现成的回调函数聚积里的全数回调函数,并将此番的参数字传送递给具备的回调函数 * */

//工具函数 var isIndexOf = Array.prototype.indexOf, //Es6 toString = Object.prototype.toString, //缓存toString方法 toSlice = Array.prototype.slice, //缓存slice方法 isFunction = { //剖断三个指标是或不是是Function return "object" === typeof document.getElementById ? isFunction = function { //ie下对DOM和BOM的识别一时常 try { return /^s*bfunctionb/.test { return false } } : isFunction = function { return toString.call === '[object Function]'; }; }卡塔尔国 { //循环遍历方法 //第多个参数表示要循环的数组,第一个参数是历次循环奉行的函数 if (arguments.length < 2 || !isFunction return; //为什么slice无效?? var list = toSlice.call, fn = arguments[1], item; while ){//未有直接决断length,加快 // 为何那边用call就足以,而apply就十三分? //消除 - apply的第贰个参数必须是叁个array对象(未有验证array-like是还是不是能够,而call未有这些供给) //apply是那般描述的:假诺 argArray 不是三个灵光的数组恐怕不是 arguments 对象,那么将以致多个 TypeError。 fn.call; } }, inArray = function (卡塔尔 { //检查实验数组中是或不是带有某项,再次来到该项索引 //预编写翻译 return isIndexOf ? function { if return isIndexOf.call; return -1; } : function { var len; if { len = array.length; i = i ? i < 0 ? Math.max : i : 0; for { if (i in array && array[i] === elem) { return i; } } } return -1; } }();

var Callbacks = function { option = toString.call === '[object Object]' ? option : {}; //使用闭包,因为各类新建的callbacks皆有协和的景况 var list = [], //回调列表 _list = [], //倘诺锁定这么些callbacks对象,则清空list,将原list置入_list fired, //是或不是试行过 firingStart, //当前回调函数列表实施的函数索引 firingLength, //回调函数的数主任度 auto, //标记是或不是自动试行,借使急需活动实行,则auto回忆着最终一遍回调的参数,那是三个很神奇的且奇葩的用法 //那么些变量用法很奇特和犀利,既包括了是还是不是钦点实施的申明,又记录了数量 //这些auto协作once差不离便是心狠手辣:试行了fire后才会自行实行,协作once能够成功:二回实行,前面不再扩张和施行代码,保证了蓬蓬勃勃组回调数据的平静和平安 stack = !option.once && [], //叁个callbacks栈,要是当前正值实施回调数组,而在实践中又新增加了回调函数,那么把新的回调函数,那么新的回调函数都会压入该栈 firing = false, //callbacks是否正在干活/试行 //触发回调函数 fire = function { //注意这么些data是个数组,假如安顿了auto形式,那么auto永久不会为false,因为auto会是个数组 auto = option.auto && data; //在此边,假若安排必要回想最终的参数,则记得那个参数 fired = true; firingIndex = firingStart || 0; firingStart = 0;//清空firingStart firingLength = list.length; //缓存list长度,外部得以访谈 firing = true; //正在实施回调函数 for (; firingIndex < firingLength; firingIndex++State of Qatar{ if (list[firingIndex].apply === false卡塔尔国 { //注意,即便安插了option.auto里存在函数,那么add(State of Qatar代码里有生机勃勃段对于auto判断会一向实行本办法的代码 //大家要阻止掉那段代码,所以设置auto为false auto = false; break; }//当函数重临false,终止实施后续队列 } firing = false; //标记情形已经实施落成回调函数[stack里面包车型客车函数还没施行] //倘若那几个栈在未曾配备once的动静下自然是[],所以自然存在 //这里主要功用是,若无安顿once,则拦截上面包车型客车代码,假使安插了once,推行完代码清空数据 if { if //先把上边清空list状态的代码拦截掉,再推断是或不是有栈 fire; //从栈尾部抽出,并递归fire //代码走到这里,注解已经布置了option.once,于是把list清空 list = []; else //注解未有配置auto,然而配置了once,那么祭出终超级大法,间接废了这一个callbacks对象 self.disable(卡塔尔(قطر‎; }; var self = { add: function (卡塔尔(قطر‎ {//增添三个回调函数 if { var start = list.length; (function addCallback { each { if {//是函数,则压入回调列表 list.push; //注意typeof 和Object.prototype.toString是不等同的 } else if === '[object Array]'卡塔尔{//要是是个数组,则递归压入回调列表,那个论断舍弃了array-like addCallback; } if //尽管当前正有回调函数在试行,那么供给更新当前回调函数列表的length,不然那一个新压入的回调函数就能够被擦过。 firingLength = list.length; else if {//就算当前从未推行回调函数,况兼必要机关试行//注意这里是给firingStart赋值,上面fire方法中正在利用的是firingIndex,这里不会默化潜移到地点代码的试行线路 firingStart = start; //施行我们新投入的小同伴 fire; } return this; }, fire: function (卡塔尔(قطر‎ {//触发回调函数 self.fireWith; return this; }, fireWith: function {//触发回调函数,并内定上下文 //假诺配置了once,stack将为undefined,而once又须求有限支撑只实行一回,所以假设施行过一回,这里的代码不会再施行if (list && { //修正参数 //在那,context索引为0 //而参数列表索引为2 //转换为数组访问是因为对象表示进一层的消功耗源,在顶层的fire(State of Qatar代码中有auto[回忆参数,自动施行]本条职能,纵然运用对象则成本了更加大的内存args = [context, args ? args.slice && args.slice() || toSlice.call : [] ]; fire; } return this; }, remove: function (卡塔尔国 {//移除四个回调函数 if { each(arguments, function { var index; //大概有多项,index能够在循环爱慕味检索的约束,从前检索的过的能够毫不再找找 while ((index = inArray > -1卡塔尔 { list.splice; if { //保险下边fire中正在实行的函数列表能够科学运转,fire中设定全局这么些变量为的就是这里能够异步移除 if (index <= firingLength卡塔尔国//修正长度 firingLength--; if (index <= firingLengthState of Qatar//改进索引 firingIndex--; } } }State of Qatar; } return this; }, has: function {//是还是不是含有三个回调函数 return fn ? inArray > -1 : list && list.length; }, empty: function (卡塔尔(قطر‎ {//清空那些callbacks对象 list = []; firingLength = 0; return this; }, disable: function (){//废掉那一个callbacks对象,后续的回调函数列表不再实践 list = stack = auto = undefined; return this; }, disabled: function (卡塔尔(قطر‎ {//是或不是早就废掉 return !list; //转换为boolean }, lock: function {//锁定或解锁那几个callbacks对象 //无参,决断那一个callbacks是不是被锁定 if return !!_list; if {//锁 _list = stack && list.concat || list; list = undefined; } else {//解锁,jQuery并未提供解锁功能,解锁让Callbacks变得不安宁 list = _list; _list = undefined; } return this; }, fired: function (卡塔尔(قطر‎{//那一个callbacks是不是举行过 //调换为boolean,包罗undefined,null,''等 return !!fired; } }; return self; }; window.$ = window.$ || {}; window.$.Callbacks = window.Callbacks = Callbacks;};

下载

Github:

以上就是本文给大家分享的全体内容了,希望大家能够钟爱。

$(function(){
    // 定义多少个就要增至回调列表的回调函数fn1,fn2,fn3       
    function fn1(arg){
        console.log( 'fn1 says:' + arg );
        // 在fn1中试行Callbacks.add操作,当时Callbacks函数内部的firingLength将会得到更新
        $callbacks.add(fn2);
    }
    function fn2(arg){
        console.log( 'fn2 says:' + arg );
    }
    function fn3(arg){
        console.log( 'fn3 says:' + arg );
    }
   
    // Callbacks传递了memory
    // 也足以如此使用$.Callbacks({ memory: true }卡塔尔;
    var $callbacks = $.Callbacks('memory');
   
    // 将fn1增至回调列表中,因为在fn1中有试行了add(fn2State of Qatar操作,因而回调列表中的回调为fn1,fn2
    $callbacks.add(fn1);
   
    // output: fn1 says:foo
    // output: fn2 says:foo
    $callbacks.fire('foo');
   
    // 将以前fire的参数字传送递给近来扩大的回调fn3,并施行fn3
    // output: fn3 says:foo
    $callbacks.add(fn3);
   
    // 再实行一回fire,注意当时回调列表中的回调叁回是fn1,fn2,fn3,fn2
    // output: fn1 says:baz
    // output: fn2 says:baz
    // output: fn3 says:baz
    // output: fn2 says:baz
    // 倘使愿意回调列表中独有fn1,fn2,fn3,只需在Callbacks函数中传出unique
    $callbacks.fire('baz');
});

3、remove源码

// Remove a callback from the list
        remove: function() {
            if ( list ) {
                jQuery.each( arguments, function( _, arg ) {
                    var index;
                    while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                        list.splice( index, 1 );//主要就是splice删除操作
                        // Handle firing indexes
                        if ( firing ) {
                            if ( index <= firingLength ) {
                                firingLength--;
                            }
                            if ( index <= firingIndex ) {
                                firingIndex--;
                            }
                        }
                    }
                });
            }
            return this;
        },

认清这几个Callbacks是还是不是业已被废掉:要是您依旧不信Callbacks是还是不是真正笔者捐躯,那么这几个主意能够让您安然。lock

// Convert String-formatted options into Object-formatted ones and store in cache
function createOptions( options ) {
    // optionsCache[ options ] 用于缓存 object所援引的值
    var object = optionsCache[ options ] = {};
    jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
        object[ flag ] = true;
    });
    return object;
}

6、fire(卡塔尔国可以传参

参数作为各样回调函数的实参

function aaa(n) {
            alert("aaa "+n);
        }
        function bbb(n) {
            alert("bbb "+n);
        }
        var cb = $.Callbacks();
        cb.add(aaa);
        cb.add(bbb);
        //fire传参
        cb.fire("hello"); //弹出aaa hello 和bbb hello

移除一个Callbacks中的三个函数:既然有了增进,那么大家也应有提供反悔的方案,我们是何等的友善,容忍着别人过去所做的总体。has

二、jQuery.Callbacks内部中firing为true的实例
1、在Callbacks.add中firing为true的实例

二、原理图

Callback选取四个参数,能够有4个筛选,once,memory,unique,stopOnFalse。

self单体有那个方法:add,remove,has,empty,disable,disabled,lock,locked, fireWith,fire,fired。

list=[]数组变量,用来访谈回调函数。fire的时候对其循环调用。

add:push数组

fire:调用fireWith,fireWith允许传参,fire可传可不传。

fireWith:调用私有函数fire,在个人函数fire中for循环list。

remove:splice数组。

4个参数:

  • once针对fire(卡塔尔(قطر‎只循环三回
  • memory 针对add,功效到add上,add时推断有memory就去实行fire。
  • unique 针对add,增添的时候就能够去重
  • stopOnFalse 针对fire,在for循环时遇到false,立刻跳出循环

新蒲京娱乐场 4

Callbacks本质就是决定函数有序的推行,Javascript是单线程引擎,也就说,javascript同期只会有豆蔻梢头处代码在运作——即正是Ajax、setTimeout。 那三个函数看起来好像都是异步的,其实并非那样,浏览器在运维javascript代码的时候,那几个代码都会被有序的压入三个系列中,当你运营Ajax的时候,浏览器会把Ajax 压入代码队列,浏览器在管理javascript代码是从这些代码队列中三个多少个替代码试行的——Callbacks,迎合了这种单线程引擎。

var optionsCache = {},
    // Used for splitting on whitespace
    core_rnotwhite = /S+/g;

2、callback也足以收到组合的款式

 function aaa() {
            alert(1);
        }
        function bbb() {
            alert(2);
        }
        //组合使用,只执行一次,并且弹出1 2
        var cb = $.Callbacks('once memory');
        cb.add(aaa);
        cb.fire(); //1
        cb.add(bbb);
        cb.fire();

源码中:
传入了 once和memory后,

options={once:true,memory:true}
optionCache={

"once memory":{once:true,memory:true}
}

Copyright © 2015-2019 http://www.carrefourstation.com. 澳门新莆京手机网站-新蒲京娱乐场有限公司 版权所有