queue模塊在jQuery中分在Effects中,搜索整個庫會發現queue也僅在特效模塊effects.js中被使用。jQuery抽取出獨立的命名空間給queue,說明除了內部Effects模塊使用外,客戶端程序員可以充分發揮聰明才智使用queue來構建非動畫API。
queue模塊向外開放的API分別是
- 掛在$上的$.queue、$.dequeue、$._queueHooks(僅內部)
- 掛在jQuery對象上的有queue、dequeue、delay、clearQueue、promise
按照jQuery的慣例,掛在$上的方法屬於低級API,掛在jQuery對象上的才是經常使用的。
一般低級API是為高級API服務的,即 queue內部會使用$.queue, dequeue內部會使用$.dequeue。這里實際是實現為一個隊列,$.queue是入列,$.dequeue是出列。
一、$.queue
這個方法有兩個作用,它既是setter,又是getter。第一個參數elem是DOM元素,第二個參數type是字符串,第三個參數data可以是function或數組。
1. 設置指定名字的queue
function cb1() {alert(1)} function cb2() {alert(2)} var arr = [cb1, cb2]; $.queue(el, 'mx', cb1); // 第三個參數為function $.queue(el, 'xm', arr); // 第三個參數為數組
2. 這時可以取到存入的callbacks
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
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對象
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)進行最后的一個清理工作,
if ( !startLength && hooks ) { hooks.empty.fire(); }
hooks.empty是一個jQuery.Callbacks對象,而它則是定義在$._queueHooks里
_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時會報錯。如下
var p = $('p')[0]; $.queue(p, 'mx1', {}); // 注意第三個參數是對象,非function $.dequeue(p, 'mx1'); // fn.call 報錯,因為fn不是function
三、queue
知道了$.queue,queue就很好理解了,它無非是內部調用了下$.queue。queue比$.queue 少了第一個參數,內部使用this代替第一個參數。
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"
var queue = $p.queue('mx'); // [ff1, ff2, ff3]
還有個技巧就是,如果使用jQuery默認的隊列"fx",可以只傳data
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出列執行下,源碼如下
if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); }
四、dequeue
dequeue則更是未添加任何特殊處理,直接調用的$.dequeue,見源碼
dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); },
五、delay
delay用來延遲后續添加的callback的執行,第一個參數time是延遲時間(另可使用"slow"和"fast"),第二個是隊列名。
function cb() { console.log(1); } var $p = $('p'); $p.delay(2000, 'mx').queue('mx', cb); $p.dequeue('mx'); // 2秒后輸出1
如果是這樣
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
顧名思義,清空所有隊列。沒什么好說的,源碼如下,直接使用一個空數組覆蓋之前的數組隊列了。
clearQueue: function( type ) { return this.queue( type || "fx", [] ); },
七、promise
這個方法返回一個promise對象,promise對象既是前面提到的Deferred對象的閹割版。你可以使用done、fail、progress添加,但不能觸發。用在queue模塊里有特殊意義,比如done它指queue里所有function都執行后才執行done添加的。如
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)
注:閱讀版本為1.9.1