Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施

Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用

Queue队列

队列是一种特殊的线性表,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队)。队列的特点是先进先出(FIFO-first in first out),即最先插入的元素最先被删除。

为什么要引入队列?

我们知道代码的执行流有异步与同步之分,例如

var a = 1;

setTimeout(function(){
a = 2;
},0) alert(a) //

我们一直习惯于“线性”地编写代码逻辑,但是在JavaScript编程几乎总是伴随着异步操作:

setTimeout,CSS3 Transition/Animation,ajax,dom的绘制,postmessage,Web Database等等,大量异步操作所带来的回调函数,会把我们的算法分解地支离破碎

之前我们说过对于异步+回调的模式,怎么“拉平”异步操作,使之跟同步一样,因为异步操作进行流程控制的时候无非避免的要嵌套大量的回调逻辑,所以就会出现promises约定了

那么jQuery引入队列其实从一个角度上可以认为:允许一系列函数被异步地调用而不会阻塞程序

$("#Aaron").slideUp().fadeIn()

这是jQuery的一组动画链式序列,它的内部其实就是一组队列Queue,所以队列和Deferred地位类似, 是一个内部使用的基础设施,当slideUp运行时,fadeIn被放到fx队列中,当slideUp完成后,从队列中被取出运行。queue函数允许 直接操作这个链式调用的行为。同时,queue可以指定队列名称获得其他能力,而不局限于fx队列


jQuery提供了2组队列操作的API:

  • jQuery.queue/dequeue
  • jQuery.fn.queue/dequeue

但是不同与普通队列定义的是:jQuery.queue和jQuery.fn.queue不仅执行出队操作,返回队头元素,还会自动执行返回的队头元素

fn是扩展在原型上的高级API是提供给实例使用的,.queue/.dequeue, 其内部是调用的$.queue,$.dequeue静态的底层方法实现入列与出列

$.queue : 显示或操作匹配的元素上已经执行的函数列队

这个方法有两个作用,它既是setter,又是getter。第一个参数elem是DOM元素,第二个参数type是字符串,第三个参数data可以是function或数组。

var body = $('body');
function cb1() {alert(1)}
function cb2() {alert(2)} //set
$.queue(body, 'aa', cb1); // 第三个参数为function
$.queue(body, 'aa', cb2); //get
$.queue(body, 'aa') //[function ,function]

这个方法有点类型get有点类似队列的push操作,jQuery的方法的接口重载是非常严重的,经常同一个接口即是set也是get,不管符不符合基本原则,但是它却很实用

无非就是把数据给缓存起来,为什么载体是一个jQuery对象,因为保存数据的手段是通过data数据缓存实现的

data_priv = new Data();
queue: function(elem, type, data) {
var queue;
if (elem) {
type = (type || "fx") + "queue";
queue = data_priv.get(elem, type);
// Speed up dequeue by getting out quickly if this is just a lookup
if (data) {
if (!queue || jQuery.isArray(data)) {
queue = data_priv.access(elem, type, jQuery.makeArray(data));
} else {
queue.push(data);
}
}
return queue || [];
}
},

data与jQuery对象之间是通过uuid建立了一个无耦合的映射关系,具体可以翻阅之前的关于“数据缓存

源码有一个默认处理

type = (type || "fx") + "queue"

可见是专职供fx动画队列处理的

$.dequeue : 匹配的元素上执行队列中的下一个函数

var body = $('body');
function cb1() {console.log(11111)}
function cb2() {console.log(22222)} //set
$.queue(body, 'aa', cb1); // 第三个参数为function
$.queue(body, 'aa', cb2); $.dequeue(body, 'aa') //
$.dequeue(body, 'aa') //

出列就有点类似shift的操作,但是不同的是还会执行这个cb1与cb2

将回调函数出列执行,每调用一次仅出列一个,因此当回调有N个时,需要调用$.dequeue方法N次元素才全部出列

来看看源码:

var queue = jQuery.queue(elem, type),
startLength = queue.length,
fn = queue.shift(),
hooks = jQuery._queueHooks(elem, type),
next = function() {
jQuery.dequeue(elem, type);
};

知道原理了, 这个就很简单了,通过queue的get取出队列的所有数据,判断一下长度,然后截取出第一个,然后做好一个预处理生成下一个的next

这里有一个hooks?

仔细分析下这个内部queueHooks

_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() {
data_priv.remove(elem, [type + "queue", key]);
})
});
}

我们说了dequeue不仅是取出来还需要执行,在执行的时候把next与hooks传递给外部的回调,

这就是js的逻辑上的很绕的地方,在内部可以传递一个引用出去,又能提供外部调用或者执行

fn.call(elem, next, hooks)

因为传递了next,所以我们的代码可以这样改

var body = $('body');
function cb1(next,hoost) {
console.log(11111)
next() //执行了cb2 //22222
} function cb2() {
console.log(22222)
} //set
$.queue(body, 'aa', cb1); // 第三个参数为function
$.queue(body, 'aa', cb2); $.dequeue(body, 'aa')

next内部仍然调用$.dequeue,这样可以接着执行队列中的下一个callback

$.dequeue里的hooks是当队列里所有的callback都执行完后(此时startLength为0)进行最后的一个清理工作

if ( !startLength && hooks ) {
hooks.empty.fire();
}

钩子其实就是jQuery.Callbacks对象,可以实现一个收集器的功能,至于在什么情况下时候,之后动画中开始分析


所以队列的本质是利用Array的push和shift来完成先进先出(First In First Out),但是这个方法的缺点也很明显,无法单独做一个独立的模块处理,因为它必须要跟jQuery对象吻合,而且对传递的数据只能是函数

jQuery源码分析系列(38) : 队列操作的更多相关文章

  1. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  2. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  3. jQuery源码分析系列(转载来源Aaron.)

    声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...

  4. jQuery源码分析系列——来自Aaron

    jQuery源码分析系列——来自Aaron 转载地址:http://www.cnblogs.com/aaronjs/p/3279314.html 版本截止到2013.8.24 jQuery官方发布最新 ...

  5. jQuery源码分析(九) 异步队列模块 Deferred 详解

    deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,比如一些Ajax操作,动画操作等.(P.s:紧跟上一节:https://www.cnblogs.com/grea ...

  6. jQuery 源码分析(二十一) DOM操作模块 删除元素 详解

    本节说一下DOM操作模块里的删除元素模块,该模块用于删除DOM里的某个节点,也可以理解为将该节点从DOM树中卸载掉,如果该节点有绑定事件,我们可以选择保留或删除这些事件,删除元素的接口有如下三个: e ...

  7. jQuery 源码分析(二十) DOM操作模块 插入元素 详解

    jQuery的DOM操作模块封装了DOM模型的insertBefore().appendChild().removeChild().cloneNode().replaceChild()等原生方法.分为 ...

  8. jQuery 源码分析(十二) 数据操作模块 html特性 详解

    jQuery的属性操作模块总共有4个部分,本篇说一下第1个部分:HTML特性部分,html特性部分是对原生方法getAttribute()和setAttribute()的封装,用于修改DOM元素的特性 ...

  9. jQuery 源码分析(十五) 数据操作模块 val详解

    jQuery的属性操作模块总共有4个部分,本篇说一下最后一个部分:val值的操作,也是属性操作里最简单的吧,只有一个API,如下: val(vlaue)        ;获取匹配元素集合中第一个元素的 ...

随机推荐

  1. [翻译svg教程]svg中的circle元素

    svg中的<circle> 元素,是用来绘制圆形的,例如 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= ...

  2. 20161023 NOIP 模拟赛 T2 解题报告

    Task 2.回文串计数 (calc.pas/calc.c/calc.cpp) [题目描述] 虽然是一名理科生,Mcx常常声称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名的热爱,这也促使他 ...

  3. 【尺取】POJ 3320

    POJ 3320 Jessica's Reading Problem 题意:一本书P页,第i页有ai知识点,问你至少从某一处开始连续要翻多少页才能复习完所有的知识点,不能跨页翻. 思路:<挑战程 ...

  4. VMware Workstation 12序列号

    VMware Workstation 12序列号:5A02H-AU243-TZJ49-GTC7K-3C61N 就好像之前微软,让大家用盗版一样,这样可以更快的拥有市场占有率.事实上,输入key即可永久 ...

  5. 跨域无法获取自定义header的问题

    同域的时候,header里面的参数可以随便自己定义.服务端都是可以获取的. 但是跨域的时候,除了设置 <add name="Access-Control-Allow-Origin&qu ...

  6. Django发送邮件

    1. 配置相关参数 如果用的是 阿里云的企业邮箱,则类似于下面: 在 settings.py 的最后面加上这些 EMAIL_BACKEND='django.core.mail.backends.smt ...

  7. CI框架,源代码一次性判断获取post(get)数据是否有某个字段值为空方法

    一.以下是CI框架 1.把所有的要接收的字段放在数组中 例: 我要接收:id,name,age,mobile 等字段 $req = array('id','name','age','mobile'); ...

  8. 【转】Web测试方法

    看到好文章,拿过来给大家分享分享! 一.输入框 1.字符型输入框: (1)字符型输入框:英文全角.英文半角.数字.空或者空格.特殊字符“~!@#¥%……&*?[]{}”特别要注意单引号和&am ...

  9. vs2013 无法打开 源 文件 "SDKDDKVer.h"

    使用vs2013开发 win32相关的程序的时候,回报很多属性未定义或者文件找不到的错误 例如构建 控制台程序就会报: vs2013 无法打开 源 文件 "SDKDDKVer.h" ...

  10. Eclipse搭建c环境(CDT)二

    Eclipse 编辑c程序环境的搭建主要为其安装CDT插件即可 Eclipse搭建CDT步骤如下: 1.首先配置好java环境,为后续运行eclipse做准备 (略) 2.下载并安装eclipse(这 ...