zoukankan      html  css  js  c++  java
  • jQuery1.11源码分析(10)-----Callbacks模块

    Callbacks模块实质上就是一个回调函数队列(当然吹得很牛逼。。比如“提供了一种强大的方法来管理回调函数队列”),之所以介绍它是因为后面的Derferred模块基于它。

    Callbacks生成时接收四个设置:once(只触发一遍),memory(记录前一次的触发传入参数,disable时是否清空队列),unique(确保队列中同样的函数只有一个),stopOnFalse(当调用某一个回调函数返回false时则停止触发)

    例:jQuery.Callbacks('once memory')

    Callbacks模块还有几个API,add,remove,has,empty,disable,lock,fire,fireWith(根据指定的上下文触发),以及两个状态判断函数,locked和disabled。

    这几个API的用法就像名字所述的那样,增加啊,移除啊之类的。。更多信息可以看文档

    这个模块没什么难度,在编写时主要有两个点需要考虑:1,当我添加或者删除某个函数时,该队列正在触发怎么办?2,当我要触发某一个队列时,该队列正在触发怎么办?

    答:记录状态,做处理即可

    //因为队列可能在调用时被改变,所以需要考虑两种状态,没调用和调用时。

    jQuery.Callbacks = function( options ) {
    
    	// Convert options from String-formatted to Object-formatted if needed
    	// (we check in cache first)
        //这样处理一下以后调用就可以保证options存在,不会像我option&&option.xxx
    	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)
    		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存的不是fn,而是传给fn调用的arguments
            //这里名称上是stack,实际上是queue
    		stack = !options.once && [],
    		// Fire callbacks
            //data[0]是上下文
            //data[1]是传给各个回调函数的参数
    		fire = function( data ) {
    			memory = options.memory && data;
    			fired = true;
    			firingIndex = firingStart || 0;
    			firingStart = 0;
    			firingLength = list.length;
    			firing = true;
    			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                    //当传入的data[0]为数组时,函数调用时的this依然是这个数组,而非数组中的item
    				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
    					memory = false; // To prevent further calls using add
    					break;
    				}
    			}
    			firing = false;
                //这里主要考虑在执行的过程中会再次执行,所以用stack来保存传入的参数
    			if ( list ) {
    				if ( stack ) {
    					if ( stack.length ) {
    						fire( stack.shift() );
    					}
    				} else if ( memory ) {
    					list = [];
    				} 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 ) {
                                console.log('list');
                                console.log(list);
    							var type = jQuery.type( arg );
    							if ( type === "function" ) {
    								if ( !options.unique || !self.has( arg ) ) {
    									list.push( arg );
    								}
                                //当传入的参数是多维数组时递归调用,有必要这样处理吗?是后面有这种用法
    							} else if ( arg && arg.length && type !== "string" ) {
    								// Inspect recursively
                                    console.log('递归');
    								add( arg );
    							}
    						});
    					})( 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
                        //如果有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;
    						while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
    							//删除很简单就删除了
                                list.splice( index, 1 );
    							// Handle firing indexes
                                //需要考虑正在触发的情况
    							if ( firing ) {
    								if ( index <= firingLength ) {
    									firingLength--;
    								}
    								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 ) {
    				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
    			},
    			// Remove all callbacks from the list
    			empty: function() {
    				list = [];
    				firingLength = 0;
    				return this;
    			},
    			// Have the list do nothing anymore
    			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 ) {
    				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;
    			},
    			// To know if the callbacks have already been called at least once
    			fired: function() {
    				return !!fired;
    			}
    		};
    
    	return self;
    };
    
  • 相关阅读:
    第十四周课程总结&实验报告(简单记事本的实现)
    第十三周课程总结
    第十二周
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
    第六周&java实验报告四
    课程总结
  • 原文地址:https://www.cnblogs.com/suprise/p/3662258.html
Copyright © 2011-2022 走看看