jQuery源码分析系列(38) : 队列操做

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

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

 

Queue队列ajax

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

 

为何要引入队列?编程

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

var a = 1;

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

alert(a) //1

咱们一直习惯于“线性”地编写代码逻辑,可是在JavaScript编程几乎老是伴随着异步操做:数组

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

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

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

$("#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')  //11
$.dequeue(body, 'aa')  //22

出列就有点相似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对象吻合,并且对传递的数据只能是函数

相关文章
相关标签/搜索