博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery.Callbacks源码解读
阅读量:5321 次
发布时间:2019-06-14

本文共 12006 字,大约阅读时间需要 40 分钟。

序言:

最近在学习jQuery.Callbacks对象,看jQuery.Callbacks的API文档,不是很懂,因此看看其源码部分,理解其使用方法,记录下自己在阅读源码时的记录并分享给大家。

有理解不透的地方望同仁指点,代码来源:jQuery 1.9.1版本。作者:,欢迎转载,转载时请注明出处并附上

 

一、源码解读

/* * 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 * */var optionsCache = {},    // Used for splitting on whitespace    core_rnotwhite = /\S+/g;// Convert String-formatted options into Object-formatted ones and store in cachefunction createOptions( options ) {    // optionsCache[ options ] 用于缓存 object所引用的值    var object = optionsCache[ options ] = {};    jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {        object[ flag ] = true;    });    return object;}jQuery.Callbacks = function( options ) {    // 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 );    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;};

 

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

1、在Callbacks.add中firing为true的实例

$(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(fn2)操作,因此回调列表中的回调为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');});

 

2、在Callbacks.fireWith中firing为true的实例

$(function(){        function fn1(arg){        console.log( 'fn1 says:' + arg );    }    function fn2(arg){        console.log( 'fn2 says:' + arg );        $callbacks.fireWith(window, ['yjh']);                // 一定要执行这一步,否则将会陷入死循环        $callbacks.remove(fn2);    }        var $callbacks = $.Callbacks();    $callbacks.add(fn1);        // output: fn1 says:foo    $callbacks.fire('foo');        $callbacks.add(fn2);        // output: fn1 says:baz    // output: fn2 says:baz    // output: fn1 says:yjh    $callbacks.fire('baz');});

 

转载于:https://www.cnblogs.com/yangjunhua/archive/2013/04/11/3014368.html

你可能感兴趣的文章
SDUTOJ3754_黑白棋(纯模拟)
查看>>
php中的isset和empty的用法区别
查看>>
Android ViewPager 动画效果
查看>>
把word文档中的所有图片导出
查看>>
ubuntu 18.04取消自动锁屏以及设置键盘快捷锁屏
查看>>
Leetcode 589. N-ary Tree Preorder Traversal
查看>>
机器学习/深度学习/其他开发环境搭建记录
查看>>
判断是否为空然后赋值
查看>>
正则表达式
查看>>
pip install torch on windows, and the 'from torch._C import * ImportError: DLL load failed:' s...
查看>>
arcgis api 4.x for js 结合 Echarts4 实现散点图效果(附源码下载)
查看>>
YTU 2625: B 构造函数和析构函数
查看>>
apache自带压力测试工具ab的使用及解析
查看>>
C#使用Xamarin开发可移植移动应用(2.Xamarin.Forms布局,本篇很长,注意)附源码
查看>>
jenkins搭建
查看>>
C#中使用Split分隔字符串的技巧
查看>>
加固linux
查看>>
IPSP问题
查看>>
10.17动手动脑
查看>>
WPF中Image显示本地图片
查看>>