zoukankan      html  css  js  c++  java
  • jquery中的callbacks之我见

    callbacks是jquery的核心之一。

    语法如下:

    jQuery.Callbacks( flags )   flags 类型: String 一个用空格标记分隔的标志可选列表,用来改变回调列表中的行为。

    once: 确保这个回调列表只执行( .fire() )一次(像一个递延 Deferred).

    memory: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred).

    unique: 确保一次只能添加一个回调(所以在列表中没有重复的回调).

    stopOnFalse: 当一个回调返回false 时中断调用

    使用案例:

    function fn1(val) {
            console.log('fn1 says ' + val);
        }
        function fn2(val) {
            console.log('fn2 says ' + val);
            return false;
        }
        var cbs = $.Callbacks('once memory');
        cbs.add(fn1);
        //第一次fire会缓存传入的参数
        cbs.fire('foo'); //fn1 says foo
        //fire过一次之后,以后的add都会自动调用fire,传入的参数是上次fire传入的'foo'
        cbs.add(fn2); //fn2 says foo
     function fn1(val) {
            console.log('fn1 says ' + val);
        }
        function fn2(val) {
            console.log('fn2 says ' + val);
            return false;
        }
        var cbs = $.Callbacks('stopOnFalse');
        cbs.add(fn2)
        cbs.add(fn1);
        cbs.fire('foo'); //fn2 says foo
      
    function fn1(val) {
            console.log('fn1 says ' + val);
        }
        function fn2(val) {
            console.log('fn2 says ' + val);
            return false;
        }
        var cbs = $.Callbacks('once');
        cbs.add(fn2)
        cbs.add(fn1);
        cbs.fire('foo'); //fn2 says foo    fn1 says foo
      
        cbs.add(fn2);
        cbs.fire("bar"); //不输出
    function fn1(val) {
            console.log('fn1 says ' + val);
        }
        function fn2(val) {
            console.log('fn2 says ' + val);
            return false;
        }
        var cbs = $.Callbacks('stopOnFalse');
        cbs.add(fn2)
        cbs.add(fn1);
        cbs.fire('foo'); //fn2 says foo    
      
        cbs.add(fn2);
        cbs.fire("bar"); //fn2 says bar

    源码分析:

    // String to Object options format cache
    var optionsCache = {};
    
        // Convert String-formatted options into Object-formatted ones and store in cache
        //20170618 huanhua 参数options="once memory"
        // 返回结果: optionsCache[once memory]={once:true,memory:true}
    function createOptions( options ) {
        var object = optionsCache[options] = {};
        //20170618 huanhua 前面已经定义正则 core_rnotwhite= /S+/g , options.match( core_rnotwhite )返回数组["once","memory"]类似这种
        jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
            object[ flag ] = true;
        });
        return object;
    }
    
    /*
     * 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:            will ensure the callback list can only be fired once (like a Deferred)
     *
     *    memory:            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:            will ensure a callback can only be added once (no duplicate in the list)
     *
     *    stopOnFalse:    interrupt callings when a callback returns false
     *
     */
    jQuery.Callbacks = function( options ) {
    
        // Convert options from String-formatted to Object-formatted if needed
        // (we check in cache first)
        options = typeof options === "string" ?
            ( optionsCache[ options ] || createOptions( options ) ) :
            jQuery.extend( {}, options );
    
        var // Flag to know if list is currently firing
            firing,
            // Last fire value (for non-forgettable lists)
            //20170618 huanhua 存储的是最后一次 fire传递的参数值
            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
            // 20170618 huanhua 回调函数的存储列表
            list = [],
            // Stack of fire calls for repeatable lists
            // 20170618 huanhua 回调函数不是只执行一次的时候,用 stack保存正在执行回调的时候,再次请求执行的 fire()中传入的参数
            stack = !options.once && [],
            // Fire callbacks
            fire = function (data) {//20170618 data是一个数组[context,arg],第一个是执行的上下午,第二个是真正的参数
                memory = options.memory && data;
                fired = true;
                firingIndex = firingStart || 0;
                firingStart = 0;
                firingLength = list.length;
                firing = true;
                for (; list && firingIndex < firingLength; firingIndex++) {
                    //20170618 huanhua 判断
                    if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
                        // 阻止未来可能由于add所产生的回调,add中有这段代码
                        //else if ( memory ) {
                       // firingStart = start; //20170618 huanhua 从列表最新添加的回调函数位置开始执行
                       // fire( memory ); //20170618 huanhua 立即执行回调函数
                      //}
                        memory = false; // To prevent further calls using add
                        break;//由于参数stopOnFalse为true,所以当有回调函数返回值为false时退出循环
                    }
                }
                firing = false;
                if (list) {
                    //20170618 huanhua 处理正在执行回调中,再次触发的 fire(),也就是同时第一个触发的 fire还没执行完,紧接着多次执行了 fire
    //在 fireWith 中有这个代码:if ( firing ) {stack.push(args);} 
         if (stack) {//20170619 huanhua  只要没有执行 disable和lock(stack=undefined) 或者 options不包含once 就会执行这里 if ( stack.length ) { fire( stack.shift() ); } } else if (memory) { //20170619 huanhua 只有在 options = "once memory" 的时候才会执行这里 list = []; } else {//20170619 huanhua options 等于 ["once","once stopOnFalse","once union"]中的任何一个的时候才会执行这里 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) { //20170618 huanhua add(fun1,fun2,fun3) jQuery.each( args, function( _, arg ) { var type = jQuery.type(arg); //20170618 huanhua 判断是函数 if (type === "function") { //20170618 huanhua !options.unique判断 当$.Callbacks('unique')时,保证列表里面不会出现重复的回调 //!self.has( arg )只要不列表里不存在,就添加到列表 if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } //20170618 huanhua 判断传递的参数是类似数组的对象,或者就是数组 // add({leng:2,0:fun1,1:fun2},{leng:1,0:fun3}); } else if ( arg && arg.length && type !== "string" ) { // Inspect recursively add( arg ); } }); })( arguments ); // Do we need to add the callbacks to the // current firing batch? //20170618 huanhua 当fire执行的时间需要比较长的时候,我们在执行 add的时候,fire也在执行,add执行完后,fire还没执行完,为了防止新加的不执行, //所以重新赋值了需要执行的回调函数个数 firingLength = list.length; if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away //20170618 huanhuaa $.CallBacks("memory"),并且还调用了 fire } else if ( memory ) { firingStart = start; //20170618 huanhua 从列表最新添加的回调函数位置开始执行 fire( memory ); //20170618 huanhua 立即执行回调函数 } } return this; }, // Remove a callback from the list //20170618 huanhua 删除指定的回调函数 remove: function () { //20170618 huanhua 判断回调函数列表是有效的 if ( list ) { jQuery.each( arguments, function( _, arg ) { var index; //20170618 huanhua index = jQuery.inArray( arg, list, index )获取需要被删除的回调函数在列表中的位置 while ((index = jQuery.inArray(arg, list, index)) > -1) { //20170618 huanhua 删除回调函数 list.splice( index, 1 ); // Handle firing indexes //20170618 huanhua 如果删除的时候在执行 fire() if (firing) { //20170618 huanhua 当被删除的回调函数的位置 <= 回调函数列表总长度的时候,删除了一个回调函数,所以 firingLength 要减一个了 if ( index <= firingLength ) { firingLength--; } //20170618 huanhua 当被删除的回调函数的位置 <= 执行到的回调函数的位置时候,删除了一个回调函数,所以 firingIndex 要减一个了 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. has: function (fn) {//回调函数是否在列表中. //20170616 huanhua !!( list && list.length ) 如果执行的 has("")/has(undefined)等等,如果 执行了 def.disable(),list就等于undefined了 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list //20170618 huanhua 清空回调函数列表 empty: function() { list = []; return this; }, // Have the list do nothing anymore //20170618 huanhua 禁用回调列表中的回调。 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)) { //20170618 huanhua 如果正在执行回调函数 //将参数推入堆栈,等待当前回调结束再调用 if ( firing ) { stack.push(args); //20170618 huanhua 如果当前不是正在执行回调函数,就直接执行 } else { fire( args ); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; };
  • 相关阅读:
    安卓版php服务器的mysql数据库增删改查简单案例
    PHP之Mysql常用SQL语句示例的深入分析
    PHP文件上传主要代码讲解
    只能输入数字的文本框-php
    Unknown column '' in 'field list'解决方案
    PHP mysqli连接MySQL数据库
    Php连接及读取和写入mysql数据库的常用代码
    mysqli 操作数据库
    类的静态变量访问
    用JS添加文本框案例代码
  • 原文地址:https://www.cnblogs.com/huaan011/p/7047165.html
Copyright © 2011-2022 走看看