queue
队列方法:执行顺序的管理。
(1)jQuery用extend扩展,是有工具方法。
jQuery.extend({
queue // 添加 类似数组的push
dequeue // 删除 类似于 shift
_queueHooks // 给传入的数据进行处理,加个 argu+queue。
});
注意:在 queue 和 dequeue 中存入的必须是一个函数,其他格式不可以。
例子:(1)
工具方法使用。
function aaa() {
alert('aaa');
}
function bbb() {
alert('bbb');
}
$.queue(document, 'q1', aaa); // 这里创建了一个q1的队列。存入了一个值,是个函数aaa
$.queue(document, 'q1', bbb); // 这里在去q1队列中加入了第二个值,是函数bbb
// $.queue(document, 'q1', [aaa, bbb]); //也可以直接存入一个数组。
console.log( $.queue(document, 'q1') ); // FF 打印出 [aaa(), bbb()]。
// 注意:queue 和 dequeue 中存入的必须是一个函数。
$.dequeue(document, 'q1'); // 弹出 aaa函数 ,出队,只是把第一个函数取出来。并执行 aaa();
$.dequeue(document, 'q1'); // 弹出 bbb函数 ,出队,又把第一项给读取出来。并执行 bbb();
//注意: dequeue,取出第一个变量,并执行它,其他的类型,无法执行。
例子:(2)
实例方法使用。
$(document).queue('p1', aaa);
$(document).queue('p1', bbb);
console.log( $.queue(document, 'p1') ); // FF 打印出 [aaa(), bbb()]。
$(document).dequeue('p1', bbb); // 打印 aaa函数。
(2)jQuery.fn.extend 扩展的是实例方法。
jQuery.fn.extend({
queue
dequeue
delay // 延迟队列
clearQueue
promise
});
思考:队列的作用。
$('#test').click(function () {
$(this).animate({ 400}, 2000); // (1)
$(this).animate({height: 400}, 2000); // (2)
$(this).animate({left: 200}, 2000); // (3)这里position要absolute
// 和上面一样。
// $(this).animate({ 400}, 2000).animate({height: 400}, 2000).animate({left: 200}, 2000);
});
// 这里的执行顺序是一次执行,不是并发执行。(1)-->(2)-->(3)
// 用定时器开启,然后执行。但是定时器是异步操作。setInterval是异步操作。
// 这个就是用队列实现的。
当使用动作函数的时候,用 queue 依次将其中对函数压入队列fx。运行的时候,就 dequeue 操作。
deferred 的是控制一个操作,queue 是控制一系列的操作。
但是 deferred 针对异步操作,延迟对象更强大一些。主要针对的是一个异步操作的控制。
queue是针对多个的。deferred很难完成多异步的操作。
在 jQuery 中 queue 主要针对的是运动的操作,去解决连续运动的这个操作。
例子
A-------------------- 使用规则
$(this).animate({ 400}, 2000).queue('fx', function () {
$(this).dequeue(); // 如果没有这个出队操作,后面的,就无法继续执行了。
}).animate({height: 400}, 2000).animate({left: 200}, 2000);
B--------------------- fx可以省略,并且如果调用函数,需要使用$(this).dequeue();
// 这里的 fx 是可以省略的,默认就是。
$(this).animate({ 400}, 2000).queue(function () {
$(this).dequeue(); // 如果没有这个出队操作,后面的,就无法继续执行了。
}).animate({height: 400}, 2000).animate({left: 200}, 2000);
C--------------------- 传入的参数,等价于dequeue。
$(this).animate({ 400}, 2000).queue(function (next) {
$(this).css('left', 200);
next();
}).animate({height: 400}, 2000).animate({left: 200}, 2000);
D------------- 利用回调函数的形式
$(this).animate({ 400}, 2000, function () {
$(this).css('left', 200);
}).animate({height: 400}, 2000).animate({left: 200}, 2000);
E-------------------- 可以通过控制queue,来控制,保证异步的顺序。
$(this).animate({ 400}, 2000).queue(function (next) {
var _this = this;
var timer = setInterval(function () {
_this.style.height = ( _this.offsetHeight + 1 ) + "px";
if (_this.offsetHeight >= 400) {
next(); // 可以控制出队的时间,没有next的执行,就不会执行下一个动作。
clearInterval(timer);
}
}, 30);
}).animate({left: 200}, 2000);
F-------------------- delay(2000) 延迟2秒钟
$('#test').click(function () {
$(this).animate({ 400}, 2000).delay(2000).animate({left: 200}, 2000);
});
G--------------------- promise 所有运动执行完成以后,执行 promise 挂载的函数。
$('#test').click(function () {
$(this).animate({ 400}, 2000).delay(2000).animate({left: 200}, 2000);
$(this).promise().done(function () {
alert('done');
});
});
});
源码:
jQuery.extend({
queue: function( elem, type, data ) {
var queue;
// 当元素存在的时候
if ( elem ) {
// 可以直接写一个type类型,不写默认就是fx
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 ) {
// 判断 queue 是否存在,如果不存在,就执行,创建一个。
// 或者存入的 data 是数组,就重写,并覆盖以前的所有方法。搞一个新的 队列 queue 。
if ( !queue || jQuery.isArray( data ) ) {
// 设定数据。
queue = data_priv.access( elem, type, jQuery.makeArray(data) );
}
// 存在,就压入。
else {
queue.push( data );
}
}
// 没有酒返回空数组,写2个参数,就返回集合。
return queue || [];
}
},
// 出队
dequeue: function( elem, type ) {
// 不写就默认fx
type = type || "fx";
// 先去得到 queue 的队列。
var queue = jQuery.queue( elem, type ), // queue 初始化。
startLength = queue.length, // 获取数组长度。
// 返回第一项。
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
// 出队的操作 next(), 跟 dequeue 一回事。
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
// 当定时器结束的时候, 进行出队。
if ( fn === "inprogress" ) {
fn = queue.shift();
startLength--; // 长度 - 1
}
// 是否是函数。
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
// 是默认情况下,就填入。
if ( type === "fx" ) {
// inprogress 针对fx。添加 inprogress
// 只有三处用了 inprogress。
// inprogress 的作用就是让队列,可以自动的进行出队的操作。
queue.unshift( "inprogress" ); // 只有第一次,添加
}
// clear up the last queue stop function
delete hooks.stop;
// fn 是队列 刚退出来的函数, 传入参数, 进行call执行。
fn.call( elem, next, hooks );
}
if ( !startLength && hooks ) {
hooks.empty.fire();
}
},
// not intended for public consumption - generates a queueHooks object, or returns the current one
// 私有的函数,清理一下缓存。
// _queueHooks 的目的就是,将fx(默认),或者用户传入的的队列名,---->> 这些都是缓存到data中了,
// 当全部结束的时候,将那些 fixqueue, 等,对咧名称,全部干掉。
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
// data_priv.get( elem, key ) 取缓存,没有酒添加一个。
//
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 ] );
})
});
}
});
实例的源码
jQuery.fn.extend({
queue: function( type, data ) {
var setter = 2;
判断是否是字符串。如果不是字符串,那么可能传入的是函数,或者数组。
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
// 查看的状态
// 传入的参数小于2.
if ( arguments.length < setter ) {
return jQuery.queue( this[0], type ); // 返回一组元素的第一项。
}
// 若果是空的话,就返回this对象,如果不是空,就要遍历了。
return data === undefined ?
this :
this.each(function() {
var queue = jQuery.queue( this, type, data );
// ensure a hooks for this queue
//这里:_queueHooks了以后,看这个是不是空的,如果不是,就填入一个数据。
jQuery._queueHooks( this, type );
// 队列第0项,不是 inprogress 就出队,只是针对第一次出队操作,后续就不会了。
// 针对animate运动的。$(document).queue('p1', aaa).$(document).queue('p1', bbb);
// 如果连续多个操作,第一个就直接执行了,然后第二个进入队列。
// inprogress干的就是这个。保证执行第一个,后面的进行入队操作,等待前面的结束,激活后面的。
// 这里,$(document).queue('p1', aaa) 执行完,就要出队,然后再执行后面的动作。
// 这是一个入队方法,但是为什么调用出队呢?
// 针对的就是这个 $(document).queue('p1', aaa) 第一个要直接运动起来。后面的压入队列,等待第一个执行结束,在进行后面的.
// 逻辑比较简单
if ( type === "fx" && queue[0] !== "inprogress" ) {
// 出队
jQuery.dequeue( this, type ); //递归了。又重新调用。
}
});
},
dequeue: function( type ) {
return this.each(function() {
jQuery.dequeue( this, type );
});
},
// Based off of the plugin by Clint Helfers, with permission.
//
// 延迟时间的。time == 600
delay: function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function( next, hooks ) {
// 这里搞了一个定时器,让你 time 时间以后,再进行出队操作。
var timeout = setTimeout( next, time );
hooks.stop = function() {
clearTimeout( timeout );
};
});
},
// 清空
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
// 这里和 Deferred 和 callbacks 里面的东西差不多。
// 就是等到运动结束了,执行个函数什么的, 让promise去执行就好了。
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
promise: function( type, obj ) {
var tmp,
// 计数
count = 1,
// Deferred 的对象
defer = jQuery.Deferred(),
elements = this,
i = this.length,
// 累加多少,就减多少。
resolve = function() {
// 直到 count == 0 的时候,才会执行这个 resolveWith--》》就是完成了---》》然后就是done。
// 这里就不存在fail了。
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
};
if ( typeof type !== "string" ) {
obj = type;
type = undefined;
}
type = type || "fx";
while( i-- ) {
tmp = data_priv.get( elements[ i ], type + "queueHooks" );
if ( tmp && tmp.empty ) { //这个队列存在的时候,就进行累加。
count++;
tmp.empty.add( resolve ); // 添加事件
}
}
resolve(); // 内部函数调用,
return defer.promise( obj );
}
});