jQuery源码之Callbacks详解

来源:互联网 发布:my sql count 限制条件 编辑:程序博客网 时间:2024/04/29 10:38

一.前言 

首先声明,这是本人个人笔记。不喜勿碰。

Callbacks在jQuery框架中是基础建设的中重之重,很多高级模块都是基于它实现的,事件模块,ajax模块。

在jQuery中回调对象模块其实就是一个队列,进行出列,插入队列的操作。只不过加了很多技巧,先贴出源码,其中有些调试笔记,可以参考下。

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 firingfiring,// Last fire value (for non-forgettable lists)memory,// Flag to know if list was already firedfired,// End of the loop when firingfiringLength,// Index of currently firing callback (modified by remove if needed)firingIndex,// First callback to fire (used internally by add and fireWith)firingStart,// Actual callback listlist = [],// Stack of fire calls for repeatable listsstack = !options.once && [],//[]// Fire callbacksfire = function( data ) {memory = options.memory && data;// 最后一次触发回调时传的参数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 ) {//执行回调函数memory = false; // To prevent further calls using addbreak;}}firing = false;if ( list ) {if ( stack ) {if ( stack.length ) {fire( stack.shift() );}} else if ( memory ) {list = [];} else {self.disable();}}},// Actual Callbacks objectself = {// Add a callback or a collection of callbacks to the listadd: function() {if ( list ) {// First, we save the current lengthvar start = list.length;(function add( args ) {jQuery.each( args, function( _, arg ) {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 recursivelyadd( 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} else if ( memory ) {firingStart = start;fire( memory );}}return this;},// Remove a callback from the listremove: function() {if ( list ) {jQuery.each( arguments, function( _, arg ) {var index;while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {list.splice( index, 1 );// Handle firing indexesif ( 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 listempty: 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 statelock: function() {stack = undefined;if ( !memory ) {self.disable();}return this;},// Is it locked?locked: function() {return !stack;},// Call all callbacks with the given context and argumentsfireWith: 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 argumentsfire: function() {self.fireWith( this, arguments );return this;},// To know if the callbacks have already been called at least oncefired: function() {return !!fired;}};return self;};
jQuery.Callbacks(arg) arg可以是once,memory,unique,这个最后返回的是一个装有API的对象,封装了其自身的属性和几个方法。只能通过开放的API进行调用

传入的传参数不一样,他们的回调函数也会有不用一样的功能。

1.once

function a(){console.log('a');}function b(){console.log('b');}var callbacks = $.Callbacks('once');callbacks.add( a );callbacks.fire();callbacks.add( b );callbacks.fire();
输出: a

只激发了第一次添加的a函数,后面新增的然后在激发也没有执行.

只要激发一次以后,就不能在激发这个回调函数队列,因为在第一次激发后 self.disable();,禁用了该队列,尽管在ADD函数进去,也不能激发。

因为disable让list = stack = memory = undefined;

2.memory

var callbacks = $.Callbacks('memory');callbacks.add( a );callbacks.fire();callbacks.add( b );
输出: a

          b

先新增a函数,在激发,然后在新增b函数,按道理讲第二次新增b函数的时候没有激发,不会执行b函数,但是这就是memory的作用,按我的理解就是记忆,新增就是执行。

只不过在第一次激发之前没有记忆功能,但是在激发一次过后就有记忆的能力,你下次在新增函数的时候就直接运行.

只要激发一次后,激活memory,然后每次add函数的时候,就会立即执行该函数.  随时都可以激发该回调队列

3.unique

var callbacks = $.Callbacks('unique');callbacks.add( a );callbacks.add( a );callbacks.fire();
输出: a

为什么只执行了一次a函数,不是add了两次吗?这就是unique的作用,相同的函数在函数队列list里面只能被添加一次

if ( !options.unique || !self.has( arg ) ) {//不唯一||不存在list.push( arg );}

在add函数到队列的时候,检查是否已经添加过,如果添加过,则无视,否则就添加家进去,随时都可以激发该回调队列


二.jQuery应用回调模块

jQuery中事件和AJAX模块都用了这个回调模块,但是大部分都是jQuery.Callbacks('once memory')来构造

once和memory合起来,能让这个回调队列有什么功能呢?

1.能多次新增函数,多次激发

2.不过每次激发完后,之前添加进去的函数在list里面都会被清空 list = [] 。  而once方式是让list = undefined.

3.就是新增进去的函数只能执行一次,执行完被清空。

三,总结

jQuery运用了很对技巧,只是一个简单的队列,却会如此神奇。

0 0
原创粉丝点击