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

jQuery1.11源码分析(10)-----Callbacks模块的更多相关文章

  1. jQuery1.11源码分析(1)-----Sizzle源码概览[原创]

    最近在啃jQuery1.11源码,上来就遇到Sizzle这个jQuery的大核心,虽然已经清楚了Sizzle的用途,先绕过去也没事,但明知山有虎偏向虎山行才是我们要做的. 本文面向的阅读对象:正在学习 ...

  2. jQuery1.11源码分析(5)-----Sizzle编译和过滤阶段[原创]

    在上一章中,我们说到在之前的查找阶段我们已经获得了待选集seed,那么这一章我们就来讲如何将seed待选集过滤,以获得我们最终要用的元素. 其实思路本质上还是不停地根据token过滤,但compile ...

  3. jQuery1.11源码分析(7)-----jQuery一些基本的API

    这篇文章比较繁杂,主要就是把jQuery源码从上到下列出来,看我的注释就好了. jQuery源码对各种加载器做了处理. //阅读这个源码是请先了解一下概念,即时函数,工厂模式 (function( g ...

  4. jQuery1.11源码分析(6)-----jQuery结构总揽

    (在看以下内容之前请先对原型链有一定的了解,比如:prototype是对象还是函数?) 在看jQuery的其他源码之前,必须对jQuery的数据结构有一定的了解. jQuery的核心很简单,jQuer ...

  5. jQuery1.11源码分析(2)-----Sizzle源码中的正则表达式[原创]

    看完了上篇,对Sizzle有了一个大致的了解,我们接下来就可以正式开始啃Sizzle的源码了.上来就讲matcher难度太大,先来点开胃菜,讲讲Sizzle中的各个正则表达式的作用吧(本来还想讲初始化 ...

  6. jQuery1.11源码分析(3)-----Sizzle源码中的浏览器兼容性检测和处理[原创]

    上一章讲了正则表达式,这一章继续我们的前菜,浏览器兼容性处理. 先介绍一个简单的沙盒测试函数. /** * Support testing using an element * @param {Fun ...

  7. jQuery1.11源码分析(9)-----初始化jQuery对象的函数和关联节点获取函数

    这篇也没什么好说的,初始化jQuery对象的函数要处理多种情况,已经被寒冬吐槽烂了.关联节点获取函数主要基于两个工具函数dir和sibling,前者基于指定的方向遍历,后者则遍历兄弟节点(真的不能合并 ...

  8. jQuery1.11源码分析(8)-----jQuery调用Sizzle引擎的相关API

    之所以把这部分放在这里,是因为这里用到了一些基本API,前一篇介绍过后才能使用. //jQuery通过find方法调用Sizzle引擎 //jQuery通过find方法调用Sizzle引擎 jQuer ...

  9. jQuery1.11源码分析(4)-----Sizzle工厂函数[原创]

    在用前两篇讲述完正则表达式.初始化.特性检测之后,终于到了我们的正餐——Sizzle工厂函数! Sizzle工厂函数有四个参数, selector:选择符 context:查找上下文 results: ...

随机推荐

  1. 优化Webstorm

    Webstorm这个编辑器还是很强大的,而且版本更新得快,支持最新的typescript,就是性能越来越低. 本文总结了一些优化Webstorm的有效方法,希望对大家有所帮助! 测试环境 Mac OS ...

  2. 原生JS、CSS实现的转盘效果(目前仅支持webkit)

    这是一个原生JS.CSS实现的转盘效果(题目在这:http://www.cnblogs.com/arfeizhang/p/turntable.html),花了半个小时左右,准备睡觉,所以先贴一段代码, ...

  3. Android学习第八弹之改变状态栏的颜色使其与APP风格一体化

    公众号:smart_android 作者:耿广龙|loonggg 点击"阅读原文",可查看更多内容和干货 导语:沉浸式状态栏,改变状态栏的颜色使之与APP风格一体化是不是感觉很漂亮 ...

  4. 【niubi-job——一个分布式的任务调度框架】----FAQ文档

    引言 本文为niubi-job的FAQ文档,该文档会无限更新.如果您在这里没有找到您想要的答案,请把问题提交到这里. FAQ 1.为什么我的所有任务总是运行在同一个节点上,而没有平均分配到所有节点上? ...

  5. DOM(一)模型中的模型节点

    <html>位于网页的顶端 它没有父辈,称之为根节点 1.元素节点(element node) 可以说,整个DOM模型都是由元素节点(element node)组成 比如文本段落元素“&l ...

  6. AngularJS——grunt神器的安装

    前言: 刚开始学 angularJS,在慕课网上看的大漠老师的视频(http://www.imooc.com/learn/156),里面刚开始讲述了前端开发-调试-测试所使用的手段和工具,本人对前端开 ...

  7. MongoDB 2.6设置访问权限、设置用户

    MongoDB已经使用很长一段时间了,基于MongoDB的数据存储也一直没有使用到权限访问(MongoDB默认设置为无权限访问限制),今天特地花了一点时间研究了一下,研究成果如下: 注:研究成果基于W ...

  8. Codeforces Round #379 (Div. 2) D. Anton and Chess 模拟

    题目链接: http://codeforces.com/contest/734/problem/D D. Anton and Chess time limit per test4 secondsmem ...

  9. [转]不再以讹传讹,GET和POST的真正区别

    原文地址:http://www.nowamagic.net/librarys/veda/detail/1919 如果有人问你,GET和POST,有什么区别?你会如何回答? 我的经历 前几天有人问我这个 ...

  10. if转换switch的小技巧

    class Program { static void Main(string[] args) { /* 对学员的结业考试成绩评测(用switch) * 成绩>=90……A * 90>成绩 ...