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;
};

最新文章

  1. xcode6如何支持空模板
  2. Linux网络编程系列-套接口选项控制
  3. hdu Code Lock
  4. jquery selector checkbox
  5. 树形DP(01组合背包The Ghost Blows Light HDU4276)
  6. 在AngularJS中学习javascript的new function意义及this作用域的生成过程
  7. Selenium2Library系列 keywords 之 _SelectElementKeywords 之 get_selected_list_value(self, locator)
  8. VbCrlf的相关说明
  9. 射频识别技术漫谈(1)&mdash;&mdash;概念、分类
  10. 校友信息管理&amp;SNS互动平台之前言、目录及说明
  11. CountDownLatch与CyclicBarrier
  12. [翻译]现代java开发指南 第三部分
  13. docker 安装与学习
  14. vim基本操作
  15. Python学习(二十一) —— 前端之JavaScript
  16. servlet 表单加上multipart/form-data后request.getParameter获取NULL(已解决)
  17. [转]【Angular4】基础(二):创建组件 Component
  18. py requests.get
  19. centos7下的glusterfs的安装与使用
  20. 大量原创视频教程分享(01)---XSL语法教程

热门文章

  1. IOS开发之——Masonry 只支持OC,暂不支持swift
  2. 城市区号SQL
  3. Stack around the variable &#39;szStr&#39; was corrupted.
  4. node 通用的中间件
  5. 1、面向对象以及winform的简单运用(开篇)
  6. localStorage和sessionStorage的区别
  7. SEO 相关知识
  8. Maven-在eclipse创建maven项目
  9. Java算法-希尔排序
  10. BZOJ-1002 轮状病毒 高精度加减+Kirchhoff矩阵数定理+递推