$.queue : 顯示或操作匹配的元素上已經(jīng)執(zhí)行的函數(shù)列隊(duì)
這個(gè)方法有兩個(gè)作用,它既是 setter,又是 getter。第一個(gè)參數(shù) elem 是 DOM 元素,第二個(gè)參數(shù) type 是字符串,第三個(gè)參數(shù) data 可以是 function 或數(shù)組。
var body = $('body');
function cb1() {alert(1)}
function cb2() {alert(2)}
//set,第三個(gè)參數(shù)是函數(shù)
$.queue(body, 'aa', cb1);
$.queue(body, 'aa', cb2);
//get
$.queue(body, 'aa') //[function ,function]
這個(gè)方法有點(diǎn)類型 get 有點(diǎn)類似隊(duì)列的 push 操作,jQuery 的方法的接口重載是非常嚴(yán)重的,經(jīng)常同一個(gè)接口即是 set 也是 get,不管符不符合基本原則,但是它卻很實(shí)用。無非就是把數(shù)據(jù)給緩存起來,為什么載體是一個(gè)jQuery對(duì)象,因?yàn)楸4鏀?shù)據(jù)的手段是通過data數(shù)據(jù)緩存實(shí)現(xiàn)的。
queue: function(elem, type, data) {
//參考右邊實(shí)現(xiàn)
}
data 與 jQuery 對(duì)象之間是通過 uuid 建立了一個(gè)無耦合的映射關(guān)系,具體可以翻閱之前的關(guān)于“數(shù)據(jù)緩存”,源碼有一個(gè)默認(rèn)處理 type = (type || "fx") + "queue" 可見是專職供fx動(dòng)畫隊(duì)列處理的。
$.dequeue : 匹配的元素上執(zhí)行隊(duì)列中的下一個(gè)函數(shù)
var body = $('body');
function cb1() {console.log(11111)}
function cb2() {console.log(22222)}
//set
$.queue(body, 'aa', cb1); // 第三個(gè)參數(shù)為function
$.queue(body, 'aa', cb2);
$.dequeue(body, 'aa') //11
$.dequeue(body, 'aa') //22
出列就有點(diǎn)類似 shift 的操作,但是不同的是還會(huì)執(zhí)行這個(gè) cb1 與 cb2,將回調(diào)函數(shù)出列執(zhí)行,每調(diào)用一次僅出列一個(gè),因此當(dāng)回調(diào)有 N 個(gè)時(shí),需要調(diào)用 $.dequeue 方法 N 次元素才全部出列,來看看源碼:
var dequeue = jQuery.queue(elem, type),
//參考右邊實(shí)現(xiàn)
};
知道原理了, 這個(gè)就很簡單了,通過 queue 的 get 取出隊(duì)列的所有數(shù)據(jù),判斷一下長度,然后截取出第一個(gè),然后做好一個(gè)預(yù)處理生成下一個(gè)的 next。
這里有一個(gè)hooks?
仔細(xì)分析下這個(gè)內(nèi)部 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不僅是取出來還需要執(zhí)行,在執(zhí)行的時(shí)候把next與hooks傳遞給外部的回調(diào),這就是js的邏輯上的很繞的地方,在內(nèi)部可以傳遞一個(gè)引用出去,又能提供外部調(diào)用或者執(zhí)行。
fn.call(elem, next, hooks)
因?yàn)閭鬟f了next,所以我們的代碼可以參考右邊代碼,next內(nèi)部仍然調(diào)用$.dequeue,這樣可以接著執(zhí)行隊(duì)列中的下一個(gè) callback,$.dequeue 里的 hooks 是當(dāng)隊(duì)列里所有的 callback 都執(zhí)行完后(此時(shí) startLength 為0)進(jìn)行最后的一個(gè)清理工作。
if ( !startLength && hooks ) {
hooks.empty.fire();
}
鉤子其實(shí)就是 jQuery.Callbacks 對(duì)象,可以實(shí)現(xiàn)一個(gè)收集器的功能,至于在什么情況下時(shí)候,之后動(dòng)畫中開始分析,所以隊(duì)列的本質(zhì)是利用 Array 的 push 和 shift 來完成先進(jìn)先出(First In First Out),但是這個(gè)方法的缺點(diǎn)也很明顯,無法單獨(dú)做一個(gè)獨(dú)立的模塊處理,因?yàn)樗仨氁?jQuery 對(duì)象吻合,而且對(duì)傳遞的數(shù)據(jù)只能是函數(shù)。