jQuery.Callbacks()回调函数队列用法详解

本文实例讲述了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相关内容感兴趣的读者可查看本站专题:《jQuery常用插件及用法总结》、《jquery中Ajax用法总结》、《jQuery表格(table)操作技巧汇总》、《jQuery拖拽特效与技巧总结》、《jQuery扩展技巧总结》、《jQuery常见经典特效汇总》、《jQuery动画与特效用法总结》及《jquery选择器用法总结》

希望本文所述对大家jQuery程序设计有所帮助。

(0)

相关推荐

  • jquery.Callbacks的实现详解

    前言 jQuery.Callbacks是jquery在1.7版本之后加入的,是从1.6版中的_Deferred对象中抽离的,主要用来进行函数队列的add.remove.fire.lock等操作,并提供once.memory.unique.stopOnFalse四个option进行一些特殊的控制. 功能介绍 jq的Callbacks模块主要是为其他模块提供服务的,他就像一个温柔的小女人,在背后默默地付出.Deferred就像一个巨人,在jq中那么的突出,但在内部,他受到Callbacks的服务.

  • jQuery AJAX回调函数this指向问题

    如在全局作用域调用一个含this的对象,此时当前对象的this指向的是window.为了让this的指向符合自己的意愿,JavaScript提供了两个方法用以改变this的指向,它们是call和apply,当然也有利用闭包来实现的方法.本文通过一个例子来说明这些问题. 先看一段演示代码,这代码只供演示用,没有实际意义. 复制代码 代码如下: //一个没有实际意义的socket连接对象 var socket = { connect: function(host, port) { alert('Co

  • Jquery版本导致Ajax不执行success回调函数

    对于使用ajax来请求数据已经不是第一次使用(一直觉得也就那么回事),就在昨天居然遇到了一个问题?项目中需要用到ajax来进行数据的请求,于是三下五除二的将ajax代码拷贝到项目中,前端,后台数据处理完毕,测试(心想可以休息下下了),谁知数据成功返回.前端没报错,后台也没错,硬是没有执行success回调函数,心凉了一半. 接下来就是找原因,查看原先代码,百度,json格式检查,终于发现问题所在 罪魁祸首居然是Jquery版本所引起的. Jquery版本:jquery-1.9.0.min.js

  • Jquery Post处理后不进入回调的原因及解决方法

    今天做一个简单的增加数据,通过Jquery的Post方法,把Json数据传到Jsp后台,处理后却怎么都不进入回调函数, $.post("addGs.do","x=" + JSON.stringify(x) ,function(d){ alert('成功'); } ,"json" ); 通过FF调试发现返回数据正常,200Ok, 没办法,又看看Jquery API,说如果最后的参数是Json时,要求返回的数据是Json格式, 会不会是返回的Json

  • jQuery源码分析之Callbacks详解

    代码的本质突出顺序.有序这一概念,尤其在javascript--毕竟javascript是单线程引擎. javascript拥有函数式编程的特性,而又因为javascript单线程引擎,我们的函数总是需要有序的执行.优秀代码常常 把函数切割成各自的模块,然后在某一特定条件下执行,既然这些函数是有序的执行,那么我们为什么不编写一个统一管理的对象,来帮助我们管理这些函数--于是,Callbacks(回调函数)诞生. 什么是Callbacks javascript中充斥着函数编程,例如最简单的wind

  • 从零学jquery之如何使用回调函数

    在类C语言中通常通过函数指针/引用的方式传递. jquery也提供类似的回调函数机制.但是如何正确传递回调函数仍然值得一提.  1.不带参数的回调 复制代码 代码如下: $.get('myhtmlpage.html', myCallBack); 其中myCallBack是函数名字.函数是javascript的基础.可以当作引用变量一样传递. 2.带参数的回调 很自然的,按照以往的经验,我们会认为带参数的回调是下面的样子: 复制代码 代码如下: $.get('myhtmlpage.html', m

  • jQuery Tips 为AJAX回调函数传递额外参数的方法

    具体到这个例子,我们希望button1和button2点击之后,用AJAX的方式取example.html的内容,然后动态更新页面的id=callbackdemo3的div HTML如下: 复制代码 代码如下: <div id="callbackdemo1"> <button id="button1">ajax load1</button><br/> </div> <div id="call

  • 自己动手实现jQuery Callbacks完整功能代码详解

    用法和$.Callbacks完全一致 , 但是只是实现了add , remove , fire , empty, has和带参数的构造函数功能,  $.Callbacks 还有disable,disabled, fireWith , fired , lock, locked 方法 代码如下: 复制代码 代码如下: String.prototype.trim = function ()        {            return this.replace( /^\s+|\s+$/g, '

  • jQuery回调函数的定义及用法实例

    本文实例讲述了jQuery回调函数的定义及用法.分享给大家供大家参考.具体分析如下: jQuery代码中对回调函数有着广泛的应用,对其有精准的理解是非常有必要的,下面就通过实例对此方法进行简单的介绍. 代码实例如下: 利用回调函数,当div全部隐藏之后弹出一个提示框. 复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="a

  • 使用jQuery中的when实现多个AJAX请求对应单个回调的例子分享

    我知道这些函数都是异步执行(asyncronously)并且会延迟一段时间返回,所以我想知道是否有一种方式,使我可以使用单个回调,并行地加载它们,就像JS加载器 curljs 所做的那样. 很幸运! 通过jQuery.when, 我可以并发地加载两个请求,只执行一次回调! jQuery 脚本正如我提到的,下面是加载脚本和一个JSON资源的用例: 复制代码 代码如下: $.when( $.getScript('/media/js/wiki-min.js?build=21eb633'),  $.ge

随机推荐