这篇文章主要介绍了 jQuery.Callbacks() 回调函数队列用法, 结合实例形式详细分析了 jQuery.Callbacks() 回调函数队列的功能、控制标志含义与相关注意事项, 需要的朋友可以参考下
jQuery 是一个兼容多浏览器的 javascript 框架,核心理念是 write less,do more(写得更少, 做得更多)。jQuery 在 2006 年 1 月由美国人 John Resig 在纽约的 barcamp 发布,吸引了来自世界各地的众多 JavaScript 高手加入,由 Dave Methvin 率领团队进行开发。
本文实例讲述了 jQuery.Callbacks() 回调函数队列用法。分享给大家供大家参考,具体如下:
1、jQuery.Callbacks
The jQuery.Callbacks() function, introduced in version 1.7, returns a multi-purpose object that provides a powerful way to manage callback lists. It supports adding, removing, firing, and disabling callbacks.
The $.Callbacks() function is internally used to provide the base functionality behind the jQuery $.ajax() and $.Deferred() components. It can be used as a similar base to define functionality for new components.
接下来,我们分别看下四个标准的控制标志。
1.1 once
创建的 callbacks 对象只允许被 fireWith() 一次 [注意:方法 fire() 是 fireWith() 的外观模式]。
- var callbacks = $.Callbacks("once");
- callbacks.add(function() {
- console.log("f1");
- });
- callbacks.fire(); //输出 "f1"
- callbacks.fire(); //什么也不发生,在源码中已经禁用了 list.disable()
1.2 memory
在调用 add() 方法时,如果这时 callbacks 队列 满足 fired && firing = false(真执行完毕) && memory(需要在构造函数指定),那么 add() 进去的回调函数会立即执行,而这个 add 进去的回调函数调用时的参数存储在 memory 变量中。memory 变量用于存储最后一次调用 callbacks.fireWith(...) 时所使用的参数 [context, arguments]。
If the Callbacks object is created with the "memory" flag as its argument, additional functions may be added and fired after the callback list is locked.
- $(function($) {
- var callbacks = $.Callbacks("memory");
- callbacks.add(function() {
- console.log("f1");
- });
- callbacks.fire(); //输出 "f1",这时函数列表已经执行完毕!
- callbacks.add(function() {
- console.log("f2");
- }); //memory作用在这里,没有fire,一样有结果: f2
- callbacks.fire(); //重新触发一次,输出 f1 f2。 firingStart = 0
- //与once一起使用
- callbacks = $.Callbacks("once memory");
- callbacks.add(function() {
- console.log("f3");
- });
- callbacks.fire(); //输出 "f3",这时函数列表已经执行完毕!
- callbacks.add(function() {
- console.log("f4");
- }); //没有fire,一样有结果: f4
- callbacks.fire(); //由于为"once",这里将什么也不执行
- });
1.3 unique
回调函数列表中的函数是否可以重复,该特性与 add() 方法有关,可以避免在回调函数列表中加入多个相同回调函数。
- var f1 = function() {
- console.log("f1");
- };
- var callbacks = $.Callbacks();
- callbacks.add(f1);
- callbacks.add(f1);
- callbacks.fire(); //输出 f1 f1
- //传递参数 "unique"
- callbacks = $.Callbacks("unique");
- callbacks.add(f1); //有效
- callbacks.add(f1); //添加不进去
- callbacks.fire(); //输出: f1
1.4 stopOnFalse
默认情况下,当执行 fireWith() 方法时,整个回调函数列表中的所有函数都会顺序执行,但如果设置了 stopOnFalse,那么当某个函数返回 false 时,后边的函数将不再执行。即使设置了 memory,再次添加的函数也不会执行了,即一旦某个函数返回 false 的情况下,会禁用 memory 功能。但如果没设置"once",再次调用 fire 可以重新触发该 callbacks。
- var f1 = function() {
- console.log("f1");
- return false
- }; //注意 return false;
- var f2 = function() {
- console.log("f2");
- };
- var callbacks = $.Callbacks();
- callbacks.add(f1);
- callbacks.add(f2);
- callbacks.fire(); //输出 f1 f2
- callbacks = $.Callbacks("memory stopOnFalse");
- callbacks.add(f1);
- callbacks.add(f2);
- callbacks.fire(); //只输出 f1
- callbacks.add(function() {
- console.log("f3");
- }); //不会输出,memory已经失去作用了
- callbacks.fire(); //重新触发,输出f1
2. memory 回调队列
- var i = 0;
- var inc = function (s){
- i++;
- alert(i +"$" + s);
- };
- var callbacks = $.Callbacks('memory');
- callbacks.add(function iteral() {
- callbacks.add(inc);
- if (i <= 1) {
- callbacks.fire(i);
- }
- });
- callbacks.fire(i);
- callbacks.add(inc);
- /*
- list = [];
- list = [it];
- --->fire(0), i=0
- 1、list = [it, inc]
- 2、push(fire(0))
- 3、i++ [inc(0)] (i=1)
- shift()--->fire(0), i=1
- 1、list = [it, inc, inc];
- 2、push(fire(1)),
- 3、i++ [inc(0)]
- 4、i++ [inc(0)] (i=3)
- shift()--->fire(1),i=3
- 1、list = [it, inc, inc, inc];
- 2、i++ [inc(1)]
- 3、i++ [inc(1)]
- 4、i++ [inc(1)] (i=6)
- --->add(inc), i=6, memory=[this,1]
- 1、i++ [inc(1)] (i=7)
- */
3、 jQuery.CallBacks 源码
说明:为了便于理解,修改了部分源码,减少了一些功能~~~
- jQuery.Callbacks = function (options) {
- // string --> object 改进建议:将未配置的参数缺省为false,而不是undefined。便于程序阅读和控制.
- options = optionsCache[options] || createOptions(options);
- var firing,
- memory, //Last fire value [context, args] (for memory lists)
- fired,
- firingLength,
- firingIndex,
- firingStart,
- list = [],
- stack = options.once === true ? false : [], // Stack of fire calls for repeatable lists
- fire = function (data) { // data --> [context, args]
- memory = !!options.memory && data; // false OR [context, arguments]
- fired = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- firing = true;
- // 这里 list 放在条件判断中是因为执行回调函数可能会改变 list 的状态,比如 this.disable()。
- for ( ; list && firingIndex < firingLength; firingIndex++) {
- if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse === true) {
- memory = false; // 禁止 memory 功能,这样调用 add() 增加新回调函数不会立即自动调用
- break;
- }
- }
- firing = false;
- if (list) {
- if (stack) {
- //进入条件: fired && firing === false && stack, 实现递归调用
- if (stack.length) {
- fire(stack.shift()); // [[context1, arguments1], [context2, arguments2]]
- }
- } else if (memory) {
- // 进入条件: fired && firing === false && stack === undefined && 有memory字段(memory变量只能通过fire()函数修改)
- // 这里的 list = [],主要是用于性能优化,以防该对象长时间不执行,占用系统内存
- list = [];
- } else {
- // 进入条件: fired && firing === false && stack === undefined && 没有memory字段, 说明必要继续保留的必要
- self.disable();
- }
- }
- },
- self = {
- add: function() {
- if (list) { //几乎所有API都应该绑定这个条件,因为我们需要处理队列
- var originLength = list.length;
- jQuery.each(arguments, function( _, arg) {
- if (jQuery.type(arg) === "function") {
- // (!(options.unique && self.has(arg))) unique字段的作用
- if (!options.unique || !self.has(arg)) {
- list.push(arg);
- }
- }
- });
- if (firing === true) {
- // 进入条件: 说明正在执行回调函数队列中,而当前执行的这个回调函数激活了add()函数,及时维护循环边界
- firingLength = list.length;
- } else if (memory) {
- // 进入条件: memory && fired && firing === false, 说明之前的 fire() 行为已经完全结束
- firingStart = originLength;
- fire(memory);
- }
- }
- return this;
- },
- remove: function() {
- if (list) {
- jQuery.each(arguments, function( _, arg) {
- var lastIndex;
- while ((lastIndex = jQuery.inArray(arg, list, lastIndex)) >= 0) {
- list.splice(lastIndex, 1);
- if (firing === true) { // 及时更新边界条件,实现智能处理
- if (lastIndex <= firingLength) {
- firingLength--;
- }
- if (lastIndex <= firingIndex) {
- firingIndex--;
- }
- }
- }
- });
- }
- return this;
- },
- has: function (func) { //这个API有两个功能,根据单一职责角度来说,应该增加一个 isNotEmpty() 接口(非空)
- return func ? jQuery.inArray(func, list) > -1 : !!(list && list.length);
- },
- empty: function() {
- list = [];
- return this;
- },
- disable: function() { // 彻底禁用该对象, stack禁用, memory禁用
- list = stack = memory = undefined;
- return this;
- },
- disabled: function() {
- return !list;
- },
- lock: function() {
- stack = undefined;
- // 如果memory没有存储调用状态,直接禁用这个对象(可能是从未调用就被锁定,或者没有memory字段)
- if (!memory) {
- self.disable();
- }
- return this;
- },
- locked: function() {
- return !stack;
- },
- fireWith: function (context, args) {
- args = args || [];
- var data = [context, args];
- if (list && (fired === false || stack) ) {
- if (firing) {
- // 进入条件: firing === true && stack 说明当前正在执行回调函数队列
- stack.push(data); // stack其实是一个队列结构,这里用 stack 有些混淆
- } else {
- // 进入条件一: firing === false && fired === false 说明从来没有 fire()过
- // 进入条件二: firing === false && fired === true && stack = [] 说明至少调用过一次,而且当前允许多次调用,可以通过lock()锁定
- fire(args);
- }
- }
- return this;
- },
- fire: function() {
- self.fireWith(this, arguments);
- return this;
- },
- fired: function() {
- return !!fired;
- }
- };
- return self;
- };
4、胡思乱想
jQuery.Callbacks() 方法的核心是 fire() 方法,将该 fire() 方法被封装在函数中不可直接访问,因此像 memory、firing、fired 这些状态对于外部上下文来说是不可更改的。
还有需要注意的是,如果回调函数中使用了 this 对象,可以直接用这个 this 来访问 self 对象的公有 API。当然,也可以用 fireWith() 自己指定 this 的引用对象。
jQuery.Callbacks() 的核心思想是 Pub/Sub 模式,建立了程序间的松散耦合和高效通信。
希望本文所述对大家 jQuery 程序设计有所帮助。
来源: http://www.phperz.com/article/17/0320/264898.html