队列模块的代码结构

静态方法jQuery下有queue,dequeue,_queueHooks这三种方法;静态方法不建议直接在外部调用;

实例方法.queue,.dequeue,.clearQueue,.delay,.promise

分别调用方法

$.dequeue(document,"q1")    //静态方法
$(document).dequeue("q1"); //实例调用方法
jQuery.extend({
  queue: function( elem, type, data ) {
    var queue;
    if ( elem ) { //当有元素时,才进行操作。比如:$.queue(document,"q1",aaa);document就是elem
      type = ( type || "fx" ) + "queue"; //如果没有传入q1那么type默认为fx,加上queue字符串
      queue = data_priv.get( elem, type ); //去数据缓存中获取此元素的q1queue属性值,第一次时,是undefined。       if ( data ) { //data就是aaa
        if ( !queue || jQuery.isArray( data ) ) { //如果取的值不存在,第一次时是不存在的。进入if语句
          queue = data_priv.access( elem, type, jQuery.makeArray(data) );//把data也就是aaa函数转换成数组形式,也就是变成[aaa()]
        } else { //当第二次执行时,也就是$.queue(document,"q1",bbb); 因为里面已经有[aaa()]了,因此直接把data(这里是bbb函数)push到q1queue属性值中。当然这里有一个例外,比如:第二次执行时,是这样的$.queue(document,"q1",[bbb]);传入的data是个数组,这时不会走这里,而是走if语句,这样的话,会把之前的[aaa()]覆盖掉,只会有[bbb()]。           queue.push( data );
        }
      }
      return queue || []; //返回这个队列,其实就是这个数组[aaa(),bbb()]
    }
  },   dequeue: function( elem, type ) { //$.dequeue(document,"q1")
    type = type || "fx";     var queue = jQuery.queue( elem, type ), //先获取这个q1队列的值
      startLength = queue.length,
        fn = queue.shift(), //取队列中的第一项
          hooks = jQuery._queueHooks( elem, type ),
               //hooks其实是元素elem在数据缓存中的一个属性对象,如果我们调用的是$.dequeue(document,"q1") 的话,
               //那么属性对象名就是q1queueHooks,属性值是{empty: jQuery.Callbacks("once memory").add(function() { data_priv.remove( elem, [ type + "queue", key ] );})}。
//因此你使用hooks.empty,其实就是q1queueHooks.empty。
        
            next = function() { //这个next方法其实就是出队
              jQuery.dequeue( elem, type );
            };     if ( fn === "inprogress" ) {       //这里为什么会出现inprogress呢?举个例子:$(this).animate({width:300},2000,function(){}).animate({left:300},2000);
      //这个代码的意思是入队两个定时器函数,第一个定时器函数是把宽度从100变成300,第二个定时器函数是把left从0变成300.如果这里只有入队操作,没有出队操作,那么这两个定时器函数都不会执行,
      //因此大家可以去看queue的实例方法,源码在下面,里面有这样一个判断:if ( type === "fx" && queue[0] !== "inprogress" ) {jQuery.dequeue( this, type );},
//animate的入队,默认队列为fx,而且它的队列的第一项不是inprogress,而是第一个定时器函数,这时进入if语句,进行出队。因此才能执行第一个定时器函数。
//那么第二个定时器函数来入队时,也会马上出队吗?不会,不然的话,两个定时器函数会同时执行了。那么第二个定时器函数为什么没有立马出队,
//是因为第一个定时器函数出队时,会在fx队列前面添加inprogress,因此第二个定时器函数入队时,fx队列的第一个项就是inprogress,因而不会进行出队操作。
// 第一个定时器函数执行完之后,就会进行再次出队,这时第二个定时器函数就会执行了。
        
      fn = queue.shift(); //如果取出的队列的第一项是inprogress,这时队列是[bbb()],因为inprogress已经出队了,就再次出队,这时bbb()出队,队列为[],fn为bbb。
      startLength--; //startLength变成1
    }     if ( fn ) { //当数组为["inprogress"]出队时,fn = undefined,startLength=0;这时就会结束队列操作了。       if ( type === "fx" ) { //当是默认队列时,也就是animate操作时,就会先往队列的前面添加inprogress
        queue.unshift( "inprogress" ); //队列变成 ["inprogress"],这时就会执行bbb(),执行完之后,又出队。
      }       delete hooks.stop;
      fn.call( elem, next, hooks ); //这里就会执行第一个定时器函数,执行完之后,就会调用next方法,进行出队。这时的队列是["inprogress",bbb()]     }     if ( !startLength && hooks ) { //当队列结束后,清理数据缓存中队列数据
      hooks.empty.fire(); //这里执行fire方法,就会触发add添加的方法,也就是data_priv.remove( elem, [ type + "queue", key ] );把缓存数据中的所有队列信息,以及q1queueHooks一起删除掉。
    }
  },   _queueHooks: function( elem, type ) {
    var key = type + "queueHooks";
    return data_priv.get( elem, key ) || data_priv.access( elem, key, {
      empty: jQuery.Callbacks("once memory").add(function() { //empty的属性值是一个Callbacks对象,Callbacks的特点是可以通过它的add方法添加函数,当调用Callbacks的fire方法时,就会执行add添加的方法。
        data_priv.remove( elem, [ type + "queue", key ] );
      })
    });
  }
});
jQuery.fn.extend({
  queue: function( type, data ) { // $(document).queue("q1",aaa);
    var setter = 2;     if ( typeof type !== "string" ) { //当type不等于字符串时,也就是这种情况时:$(document).queue(aaa);
      data = type; //data = aaa,type = "fx",setter =1
      type = "fx";
      setter--;
    }     if ( arguments.length < setter ) { //这里判断是获取,还是设置。比如:$(document).queue("q1"),这里是获取操作,因此进入if语句。
      return jQuery.queue( this[0], type ); //获取是针对一组元素的第一个元素。
    }     return data === undefined ? this : this.each(function() { //这里就是设置操作,对每个元素都进行设置
      var queue = jQuery.queue( this, type, data ); //入队操作,会在缓存系统中添加一个队列q1,队列中,入队aaa。       jQuery._queueHooks( this, type ); //设置元素的hooks对象,会在缓存系统中添加一个hooks属性,它可以移除缓存系统中与元素this,相关的队列操作的所有数据。       if ( type === "fx" && queue[0] !== "inprogress" ) { //跟静态方法的queue的思路一样。如果是动画队列,那么首次入队的时候会自动出队执行。
        jQuery.dequeue( this, type );
      }
    });
  },
  dequeue: function( type ) { //$(document).dequeue("q1"); 出队操作,是针对一组元素的。也就是说如果有多个document被匹配上,那么会对每个document都做出队操作。
    return this.each(function() {
      jQuery.dequeue( this, type );
    });
  },
  delay: function( time, type ) { //第一个参数是延迟的时间,第二个参数是哪个队列(队列的名字)延迟,我们先来举个例子说下delay方法的作用:$(this).animate({width:300},2000).delay(2000).animate({left:300},2000);这个代码的意思是:第一个定时器函数执行结束后,会延迟两秒钟,才会执行第二个定时器函数。
    time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
//jQuery.fx.speeds = {slow: 600,fast: 200,_default: 400};意思就是说,你delay里面是否写了"slow","fast",或"_default"。
//如果是,就直接调用默认的值,如果传入的是数字,那么就只用数字。     type = type || "fx";     return this.queue( type, function( next, hooks ) {
      var timeout = setTimeout( next, time ); //延迟time秒,再进行出队。意思就是time秒后,第二个定时器函数才会执行。
      hooks.stop = function() { //这个方法会清除定时器,如果执行,next方法就不会执行,也就不会出队了
        clearTimeout( timeout );
      };
    });
  },
  clearQueue: function( type ) {
    return this.queue( type || "fx", [] ); //把队列变成空数组,上面说到,如果传入数组,会覆盖队列的原数组
  },
  promise: function( type, obj ) { //type是指队列的名字,如果此type的队列全部出队后,就会执行done添加的方法。
//我们先举个例子说下这个方法的作用:$(this).animate({width:300},2000).animate({left:300},2000);$(this).promise().done(function(){alert(3)});
//这句代码的意思是,等上面两个定时器函数都执行结束后(因为他们默认处理的都是fx队列)。才会执行弹出3的函数。
    var tmp,
      count = 1,
        defer = jQuery.Deferred(), //新建一个延迟对象
          elements = this,
            i = this.length, //元素的个数,这里假设是一个document元素
              resolve = function() {
                if ( !( --count ) ) {
                  defer.resolveWith( elements, [ elements ] );
                }
              };     if ( typeof type !== "string" ) { //如果没传入队列名,就用fx默认队列
      obj = type;
      type = undefined;
    }
    type = type || "fx";     while( i-- ) { //执行一次
      tmp = data_priv.get( elements[ i ], type + "queueHooks" ); //去缓存系统找跟这个元素有关的数据
      if ( tmp && tmp.empty ) { //如果存在,就证明队列中有定时器函数要执行。进入if语句
        count++; //count等于2
        tmp.empty.add( resolve ); //当调用tmp.empty.fire方法时,就会执行resolve 方法。而这里会等fx类型的队列全部出队后(这两个定时器函数都执行结束后),才会触发fire方法,
//这时就会执行add添加的所有方法,resolve就是其中一个,于是count就会变成0(在出队列时,下面的resolve方法已经执行一次了),进入if语句,执行延迟对象的resolveWith,
//而此方法,就会触发延迟对象的done方法添加的函数,因此弹出3的函数执行。
      }
    }
    resolve(); //这里会先执行一次resolve方法,count--,变成1。
    return defer.promise( obj ); //返回这个延迟对象。
  }
});

引自:http://www.cnblogs.com/chaojidan/p/4183687.html

jquery源码学习之queue方法的更多相关文章

  1. jquery源码学习(一)——jquery结构概述以及如何合适的暴露全局变量

    jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jq ...

  2. jquery源码学习笔记三:jQuery工厂剖析

    jquery源码学习笔记二:jQuery工厂 jquery源码学习笔记一:总体结构 上两篇说过,query的核心是一个jQuery工厂.其代码如下 function( window, noGlobal ...

  3. jquery 源码学习(一)

    从上边的注释看,jQuery的源码结构相当清晰.条理,不像代码那般晦涩和让人纠结   1. 总体架构 1.1 自调用匿名函数 self-invoking anonymous function 打开jQ ...

  4. jQuery源码学习感想

    还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...

  5. 读艾伦的jQuery的无new构建,疑惑分析——jquery源码学习一

    背景: 有心学习jquery源码,苦于自己水平有限,若自己研究,耗时耗力,且读懂之日无期. 所以,网上寻找高手的源码分析.再经过自己思考,整理,验证.以求有所收获. 此篇为读高手艾伦<jQuer ...

  6. jquery 源码学习(*)

    最近在做日志统计程序,发现对方的程序是在Jquery基础上进行开发的,而公司的网站的框架是prototype.而且我也早就想了解一下Jquery源码,故决定研究Jquery源码,模拟它的方法   Jq ...

  7. jQuery源码学习笔记一

    学习jQuery源码,我主要是通过妙味视频上学习的.这里将所有的源码分析,还有一些自己弄懂过程中的方法及示例整理出来,供大家参考. 我用的jquery v2.0.3版本. var rootjQuery ...

  8. jquery 源码学习(四)构造jQuery对象-工具函数

    jQuery源码分析-03构造jQuery对象-工具函数,需要的朋友可以参考下.   作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原 ...

  9. Jquery源码学习(第一天)

    jQuery是面向对象的设计通过window.$ = window.jQuery = $; 向外提供接口,将$挂在window下,外部就可以使用$和jQuery $("#div1" ...

随机推荐

  1. android切换屏幕时的生命周期

    老版本总结: 1.不设置Activity的android:configChanges时 切屏会重新调用生命周期的方法,切横屏调用1次 切竖屏调用2次 2.设置Activity的android:conf ...

  2. 国产AR SDK介绍

    说到VR,大家都知道虚拟现实有多火.可是VR之后呢,还有AR.相较于VR,AR的应用意义更加的强大. 相信在不久的将来AR和VR将会融为一体,把现实世界的数据信息完全联通在我们的眼前.这其中的领头羊莫 ...

  3. 关于listview排序的说明

    增加了排序属性后(即设置ListViewItemSorter属性),即便是把listview的内容全部清掉(listView.Items.Clear()),然后再重新添加行(listView.Item ...

  4. Linux TC基于CBQ队列的流量管理范例

    参考了TC的很多文档,自己也整理了一篇配置记录.在实际使用过程中效果还不错,在此分享给大家以备参考.环境:局域网规模不是很大40多台机器. NAT共享上网(内网:eth0 外网:eth2)CBQ是通过 ...

  5. 新冲刺Sprint3(第一天)

    一.Sprint介绍 sprint2已经结束了,现在准备进行新一轮的冲刺--sprint3.现在简单说下sprint3的情况,正在进行的有更新商品图片和浏览商家相关信息,还有就是APP测滑栏的完善.准 ...

  6. hiho一下120周 后缀数组一·重复旋律

    后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列. 小Hi ...

  7. 怎样创建FTP服务器

    怎样创建FTP服务器 2008-05-06 08:42永远的探索|分类:操作系统/系统故障| 浏览6382次 我准备用局域网内的一台机器做FTP服务器,创建FTP服务器一定要用Windows serv ...

  8. MQTT协议的简单介绍和服务器的安装

    最近公司做的项目中有用到消息推送,经过多方面的筛选之后确定了使用MQTT协议,相对于XMPP,MQTT更加轻量级,并且占用用户很少的带宽. MQTT是IBM推出的一种针对移动终端设备的基于TCP/IP ...

  9. Streaming replication slots in PostgreSQL 9.4

    Streaming replication slots are a pending feature in PostgreSQL 9.4, as part of the logical changese ...

  10. 10-Java 网络通信

    (一) Java中的XML操作 1.XML数据格式简介: (1)XML,即可扩展标记语言(Extensible Markup Language),标准通用标记语言的子集,一种用于标记电子文件使其具有结 ...