queue模块在jQuery中分在Effects中,搜索整个库会发现queue也仅在特效模块effects.js中被使用。jQuery抽取出独立的命名空间给queue,说明除了内部Effects模块使用外,客户端程序员可以充分发挥聪明才智使用queue来构建非动画API。
queue模块向外开放的API分别是
按照jQuery的惯例,挂在$上的方法属于低级API,挂在jQuery对象上的才是经常使用的。
一般低级API是为高级API服务的,即 queue内部会使用$.queue, dequeue内部会使用$.dequeue。这里实际是实现为一个队列,$.queue是入列,$.dequeue是出列。
一、$.queue
这个方法有两个作用,它既是setter,又是getter。第一个参数elem是DOM元素,第二个参数type是字符串,第三个参数data可以是function或数组。
1. 设置指定名字的queue
1
2
3
4
5
6
|
function
cb1() {alert(1)}
function
cb2() {alert(2)}
var
arr = [cb1, cb2];
$.queue(el,
'mx'
, cb1);
// 第三个参数为function
$.queue(el,
'xm'
, arr);
// 第三个参数为数组
|
2. 这时可以取到存入的callbacks
1
2
|
var
cbs1 = $.queue(el,
'mx'
);
// [cb1]
var
cbs2 = $.queue(el,
'xm'
);
// [cb1, cb2]
|
$.queue内部使用 $._data方法,将数据保存下来。默认type/queueName使用 "fx" + queue。$.queue的实现很简单,代码不过15行,即取缓存对象queue,如果不存在则初始化为一个空对象,然后将data存入,如果存在则直接将data push到数组中。
二、$.dequeue
将回调函数出列执行,每调用一次仅出列一个,因此当回调有N个时,需要调用$.dequeue方法N次元素才全部出列。$.dequeue的第一个参数是dom元素,第二个参数是queueName
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function
ff1() {console.log(1)}
function
ff2() {console.log(2)}
function
ff3() {console.log(3)}
var
p = $(
'p'
)[0];
$.queue(p,
'mx1'
, ff1);
$.queue(p,
'mx1'
, ff2);
$.queue(p,
'mx1'
, ff3);
// 每2秒调用一次$.dequeue,依次输出1,2,3
setInterval(
function
() {
$.dequeue(p,
'mx1'
)
}, 2000);
|
回调函数的上下文是dom元素,参数是next函数和hooks对象
1
2
3
4
5
6
7
8
|
var
p = $(
'p'
)[0];
function
func(next, hooks) {
console.log(
this
);
console.log(next);
console.log(hooks);
}
$.queue(p,
'mx'
, func);
$.dequeue(p,
'mx'
);
// p, function, [object Object]
|
next内部仍然调用$.dequeue,这样可以接着执行队列中的下一个callback。$.dequeue里的hooks是当队列里所有的callback都执行完后(此时startLength为0)进行最后的一个清理工作,
1
2
3
|
if
( !startLength && hooks ) {
hooks.empty.fire();
}
|
hooks.empty是一个jQuery.Callbacks对象,而它则是定义在$._queueHooks里
1
2
3
4
5
6
7
8
9
|
_queueHooks:
function
( elem, type ) {
var
key = type +
"queueHooks"
;
return
jQuery._data( elem, key ) || jQuery._data( elem, key, {
empty: jQuery.Callbacks(
"once memory"
).add(
function
() {
jQuery._removeData( elem, type +
"queue"
);
jQuery._removeData( elem, key );
})
});
}
|
以上就是queue的全部了,本质是利用Array的push和shift来完成先进先出(First In First Out),但这里有个缺陷,jQuery的queue从1.1开始就是为effects模块服务的,因此queue里存的都是function。个人觉得如果只存function,应该对data参数做个严格类型判断,如果不是function则抛异常。但目前的版本没有做严格判断,如果我存的不是function,这样dequeue时会报错。如下
1
2
3
|
var
p = $(
'p'
)[0];
$.queue(p,
'mx1'
, {});
// 注意第三个参数是对象,非function
$.dequeue(p,
'mx1'
);
// fn.call 报错,因为fn不是function
|
三、queue
知道了$.queue,queue就很好理解了,它无非是内部调用了下$.queue。queue比$.queue 少了第一个参数,内部使用this代替第一个参数。
1
2
3
4
5
6
7
8
|
function
ff1() {console.log(1)}
function
ff2() {console.log(2)}
function
ff3() {console.log(3)}
var
$p = $(
'p'
);
$p.queue(
'mx'
, ff1);
$p.queue(
'mx'
, ff2);
$p.queue(
'mx'
, ff3);
|
这样,三个function就入列了,列名是"mx"。 取队列元素只需传一个列名如"mx"
1
|
var
queue = $p.queue(
'mx'
);
// [ff1, ff2, ff3]
|
还有个技巧就是,如果使用jQuery默认的队列"fx",可以只传data
1
2
3
4
5
6
7
|
function
ff1() {console.log(1)}
function
ff2() {console.log(2)}
function
ff3() {console.log(3)}
var
$p = $(
'p'
);
$p.queue(ff1);
$p.queue(ff2);
$p.queue(ff3);
|
另外一点,当使用默认列名"fx"时,它会调用$.dequeue出列执行下,源码如下
1
2
3
|
if
( type ===
"fx"
&& queue[0] !==
"inprogress"
) {
jQuery.dequeue(
this
, type );
}
|
四、dequeue
dequeue则更是未添加任何特殊处理,直接调用的$.dequeue,见源码
1
2
3
4
5
|
dequeue:
function
( type ) {
return
this
.each(
function
() {
jQuery.dequeue(
this
, type );
});
},
|
五、delay
delay用来延迟后续添加的callback的执行,第一个参数time是延迟时间(另可使用"slow"和"fast"),第二个是队列名。
1
2
3
4
5
6
7
|
function
cb() {
console.log(1);
}
var
$p = $(
'p'
);
$p.delay(2000,
'mx'
).queue(
'mx'
, cb);
$p.dequeue(
'mx'
);
// 2秒后输出1
|
如果是这样
1
2
3
4
5
6
7
8
9
10
|
function
ff1() {console.log(1)}
function
ff2() {console.log(2)}
var
$p = $(
'p'
);
$p.queue(
'mx'
, ff1);
$p.delay(4000,
'mx'
);
$p.queue(
'mx'
, ff2);
$p.dequeue(
'mx'
);
// 立即输出1
$p.dequeue(
'mx'
);
// 4秒后输出2
|
六、clearQueue
顾名思义,清空所有队列。没什么好说的,源码如下,直接使用一个空数组覆盖之前的数组队列了。
1
2
3
|
clearQueue:
function
( type ) {
return
this
.queue( type ||
"fx"
, [] );
},
|
七、promise
这个方法返回一个promise对象,promise对象既是前面提到的Deferred对象的阉割版。你可以使用done、fail、progress添加,但不能触发。用在queue模块里有特殊意义,比如done它指queue里所有function都执行后才执行done添加的。如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function
ff1() {
alert(1)
}
function
ff2() {
alert(2)
}
function
succ() {
alert(
'done'
)
}
$body = $(
'body'
)
$body.queue(
'mx'
, ff1);
$body.queue(
'mx'
, ff2);
var
promise = $body.promise(
'mx'
);
promise.done(succ);
setInterval(
function
() {
$body.dequeue(
'mx'
)
// 先弹出1,2,最后是"done"
}, 1500)
|