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,有兴趣的朋友也欢迎一起来分析及做适合自己的框架吧!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值