jQuery1.7中的Callbacks

严格来讲,jQuery的Callback对象只是对于回调的一种封装,使其变得更加通用,机制类似于事件,只是触发是由手工fire触发回调,当然也支持在事件的回调中触发回调列表


// String to Object flags format cache  
var flagsCache = {};  
  
// Convert String-formatted flags into Object-formatted ones and store in cache  
function createFlags( flags ) {  
    var object = flagsCache[ flags ] = {},  
        i, length;  
    flags = flags.split( /\s+/ );  
    for ( i = 0, length = flags.length; i < length; i++ ) {  
        object[ flags[i] ] = true;  
    }  
    return object;  
}  
  
  
/* 
 * 使用以下参数创建一个回调列表: 
 * 
 *  flags:  一个可选的空格间隔的列表,它将改变回调的行为 
 * 
 * 默认情况下,一个回调列表与事件回调动作相同,也可以被触发多次 
 * 
 * 可选的 flags: 
 * 
 *  once:           确保回调列表只能被执行一次 (like a Deferred) 
 * 
 *  memory:         将会保持以前的值,后续添加的回调在最新的内存状态下执行 (like a Deferred) 
 * 
 *  unique:         确保回调只被添加一次 
 * 
 *  stopOnFalse:    当有一个回调返回false时停止  
 * 
 */  
jQuery.Callbacks = function( flags ) {  
  
    // 将 flags 从 String 格式转换成 Object 格式,首先检查全局的 flags   
    flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};  
  
    var // Actual callback list  
        list = [],  
        // Stack of fire calls for repeatable lists  
        stack = [],  
        // Last fire value (for non-forgettable lists)  
        memory,  
        // Flag to know if list was already fired  
        fired,  
        // Flag to know if list is currently firing  
        firing,  
        // First callback to fire (used internally by add and fireWith)  
        firingStart,  
        // End of the loop when firing  
        firingLength,  
        // Index of currently firing callback (modified by remove if needed)  
        firingIndex,  
        // 增加一个或者多个回调到回调列表  
        add = function( args ) {  
            var i,  
                length,  
                elem,  
                type,  
                actual;  
            for ( i = 0, length = args.length; i < length; i++ ) {  
                elem = args[ i ];  
                type = jQuery.type( elem );  
                // 支持添加一个回调列表  
                if ( type === "array" ) {  
                    // Inspect recursively  
                    add( elem );  
                } else if ( type === "function" ) {  
                    // 如果不是在unique模式,或者回调列表中没有当前的回调,则添加  
                    if ( !flags.unique || !self.has( elem ) ) {  
                        list.push( elem );  
                    }  
                }  
            }  
        },  
        // 触发回调列表,fire与add都为内部函数  
        // context参数表示当前的上下文,一般使用document;args,则是向回调函数中传递的参数  
        fire = function( context, args ) {  
            args = args || [];  
            memory = !flags.memory || [ context, args ];  
            fired = true;  
            firing = true;  
            firingIndex = firingStart || 0;  
            firingStart = 0;  
            firingLength = list.length;  
            for ( ; list && firingIndex < firingLength; firingIndex++ ) {  
                //调用回调列表,stopOnFalse 模式下返回为 false 则终止回调  
                if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {  
                    memory = true; // Mark as halted  
                    break;  
                }  
            }  
            firing = false;  
            if ( list ) {  
                // 如果不是只执行一次的,则  
                if ( !flags.once ) {  
                    if ( stack && stack.length ) {  
                        memory = stack.shift();  
                        self.fireWith( memory[ 0 ], memory[ 1 ] );  
                    }  
                } else if ( memory === true ) {  
                    self.disable();  
                } else {  
                    list = [];  
                }  
            }  
        },  
        // 真正的回调对象  
        self = {  
            // 增加一个回调或者回调集合到列表中  
            add: function() {  
                if ( list ) {  
                    var length = list.length;  
                    add( arguments );  
                    // Do we need to add the callbacks to the  
                    // current firing batch?  
                    if ( firing ) {  
                        firingLength = list.length;  
                    // With memory, if we're not firing then  
                    // we should call right away, unless previous  
                    // firing was halted (stopOnFalse)  
                    } else if ( memory && memory !== true ) {  
                        firingStart = length;  
                        fire( memory[ 0 ], memory[ 1 ] );  
                    }  
                }  
                return this;  
            },  
            // 从列表中删除一个回调  
            remove: function() {  
                if ( list ) {  
                    var args = arguments,  
                        argIndex = 0,  
                        argLength = args.length;  
                    for ( ; argIndex < argLength ; argIndex++ ) {  
                        for ( var i = 0; i < list.length; i++ ) {  
                            if ( args[ argIndex ] === list[ i ] ) {  
                                // Handle firingIndex and firingLength  
                                if ( firing ) {  
                                    if ( i <= firingLength ) {  
                                        firingLength--;  
                                        if ( i <= firingIndex ) {  
                                            firingIndex--;  
                                        }  
                                    }  
                                }  
                                // Remove the element  
                                list.splice( i--, 1 );  
                                // If we have some unicity property then  
                                // we only need to do this once  
                                if ( flags.unique ) {  
                                    break;  
                                }  
                            }  
                        }  
                    }  
                }  
                return this;  
            },  
            // Control if a given callback is in the list  
            has: function( fn ) {  
                if ( list ) {  
                    var i = 0,  
                        length = list.length;  
                    for ( ; i < length; i++ ) {  
                        if ( fn === list[ i ] ) {  
                            return true;  
                        }  
                    }  
                }  
                return false;  
            },  
            // Remove all callbacks from the list  
            empty: function() {  
                list = [];  
                return this;  
            },  
            // 禁用当前的Callback  
            disable: function() {  
                list = stack = memory = undefined;  
                return this;  
            },  
            // 判断是否已不可用  
            disabled: function() {  
                return !list;  
            },  
            // 锁定当前列表状态  
            lock: function() {  
                stack = undefined;  
                if ( !memory || memory === true ) {  
                    self.disable();  
                }  
                return this;  
            },  
            // 判断是否已经装载  
            locked: function() {  
                return !stack;  
            },  
            // 通过传递context和arguments,调用所有的回调  
            fireWith: function( context, args ) {  
                if ( stack ) {  
                    if ( firing ) {  
                        if ( !flags.once ) {  
                            stack.push( [ context, args ] );  
                        }  
                    } else if ( !( flags.once && memory ) ) {  
                        fire( context, args );  
                    }  
                }  
                return this;  
            },  
            // 通过arguments在当前this上下文下,执行回调列表  
            fire: function() {  
                self.fireWith( this, arguments );  
                return this;  
            },  
            // 判断当前回调列表是否已经被执行过至少一次  
            fired: function() {  
                return !!fired;  
            }  
        };  
  
    return self;  
};  

优点:
1.对线程进行控制,一个回调函数在触发,而另一个又在删除回调的时候,作了标志位的判断
2.对状态进行传递,如果是memory的话,则 参数会进行传递
3.其中使用到jQuery的API只有一个,即 jQuery.type(elem),这个其实是可以改造成标准的javascript的,整个Callback可以抽取成一个插件的形式

将Callback单独抽取了出来,更改了两个地方:
jQuery.Callbacks = function( flags ) {  
    // ...  
}  
  
// 更改为  
  
var Callbacks = function( flags ) {  
    // ...  
};  

type = jQuery.type( elem );  
  
// 更改为:  
  
type = typeof elem; 

// 后续需要对这个作一定的判断,jQuery.type里面写的还是挺完善的 
jQuery.Callbacks 可以在jQuery的官方文档中查看:http://api.jquery.com/jQuery.Callbacks/

附件中带了callbacks.js和它的一个测试案例,callbacks.js完全独立于jQuery.js,所以它是可以用于任何一个项目中的,用于帮助用户抽取回调函数。

后续会写成具有命名空间的插件形式,并不断的完善这个库,暂时将这个库命名为ling.js,有兴趣的朋友也欢迎一起来分析及做适合自己的框架吧!

你可能感兴趣的:(jquery)