隊列是經常使用的數據結構之一,只容許在表的前端(隊頭)進行刪除操做(出隊),在表的後端(隊尾)進行插入操做(入隊)。特色是先進先出,最早插入的元素最早被刪除。html
在jQuery內部,隊列模塊爲動畫模塊提供基礎功能,負責存儲動畫函數、自動出隊並執行動畫函數,同時還要確保動畫函數的順序執行。前端
jQuery的靜態方法含有以下API:jquery
elem ;DOM元素或JavaScript對象後端
type ;隊列名稱,默認是標準動畫fx數組
data ;須要設置的隊列函數,能夠是空(返回隊列)、函數(加入隊列)或函數數組(替換隊列)promise
elem ;DOM元素或JavaScript對象緩存
type ;是隊列名稱,默認爲動畫隊列fx數據結構
writer by:大沙漠 QQ:22969969函數
jQuery/$ 實例方法(能夠經過jQuery實例調用的):源碼分析
type ;隊列名稱
data ;data是可選的函數或函數數組,參數同$.queue()的第三個參數
舉個栗子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script> </head> <body> <p>123</p> <script> function f1(){console.log('f1觸發');} //定義兩個測試函數 function f2(){console.log('f2觸發')}; $('p').queue('test',f1); //將f1入隊,隊列名稱爲test $('p').dequeue('test'); //將匹配元素的名稱爲test的函數列表出隊並執行 $('p').queue(f2); //將f2放入p匹配元素的隊列中,默認爲動畫隊列,會自動執行。 </script> </body> </html>
輸出以下:
源碼分析
jQuery的隊列是基於數據緩存模塊$.data來實現的,當調用$.queue()時回把函數列表以隊列名+'queue'爲屬性,保存在對應的DOM元素的內部緩存對象上,例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script> </head> <body> <p>123</p> <script> function f1(){console.log('f1觸發');} $('p').queue('test',f1); </script> </body> </html>
咱們能夠在控制檯裏直接從$.cache裏獲取對應的屬性,以下:
document.getElementsByTagName('p')[0][$.expando]就是例子裏p元素節點對象的$.expando屬性,該屬性的值會做爲$.cache的某個屬性,存儲着對應這個p元素的數據緩存對象(這是數據緩存模塊的內容)
$.queue和$.dequeue的實現以下:
jQuery.extend({ /*略*/ queue: function( elem, type, data ) { //返回或修改匹配元素關聯的隊列。elem是DOM元素或JavaScript對象,type是隊列名稱,data是可選的函數或函數數組 var q; if ( elem ) { type = ( type || "fx" ) + "queue"; //修正參數type,默認爲動畫隊列fx,在參數type後面加上queue表示這是一個隊列 q = jQuery._data( elem, type ); //取出參數type對應的隊列 若是以前有數據則返回該數組 不然 q等於undefined // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { //若是傳入了data參數 if ( !q || jQuery.isArray(data) ) { //若是type隊列不存在,或者type隊列存在且data是一個數組 q = jQuery._data( elem, type, jQuery.makeArray(data) ); //調用jQuery.makeArray把參數data轉換爲數組並替換隊列 } else { q.push( data ); //隊列存在且data不是一個數組則調用數組push方法把參數data放入隊列 } } return q || []; } }, dequeue: function( elem, type ) { //用於出隊並執行匹配元素關聯的函數隊列中的下一個元素 type = type || "fx"; //修正參數type,默認是"fx"; var queue = jQuery.queue( elem, type ), //獲取elem元素的type隊列 fn = queue.shift(), //調用shift方法取出隊列第一個函數 hooks = {}; //存放出隊的函數在執行時的數據 // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { //若是出隊的是佔位符"inprogress",則丟棄再從隊列頭部出一個,只有動畫隊列會設置佔位符"inprogress" fn = queue.shift(); } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { //若是是動畫隊列 queue.unshift( "inprogress" ); //則在隊列開頭添加一個佔位符"inprogress",表示動畫函數正在執行當中 } jQuery._data( elem, type + ".run", hooks ); //設置內部數據type+".run",表示參數type對應的隊列正在執行,值是hooks,它會被做爲第二個參數傳遞給出隊的函數 fn.call( elem, function() { jQuery.dequeue( elem, type ); }, hooks ); //調用函數方法call執行出隊的函數,elem是函數執行的上下文,即關鍵詞this指向的對象;第二個參數是封裝了jQuery.dequeue( elem, type )的函數,不會自動執行,須要在出隊的函數返回前手動調用next() } if ( !queue.length ) { //若是參數type對應的隊列在出隊後成爲空隊列,即全部函數都已經出隊並執行 jQuery.removeData( elem, type + "queue " + type + ".run", true ); //調用jQuery.removeData()方法移除參數type對應的數據緩存對象 handleQueueMarkDefer( elem, type, "queue" ); //檢查匹配元素關聯的隊列(type+"queue")和計數器(type+"mark")是否完成,若是完成則觸發方法.promise()中的計數器 } } });
type默認等於fx,jQuery的動畫效果也是基於Queue實現的,這個fx默認就是動畫效果,對於jQuery/$ 實例方法來講,它是調用jQuery的靜態方法來實現的,以下:
jQuery.fn.extend({ queue: function( type, data ) { //返回第一個匹配元素的函數隊列,或修改全部匹配的元素關聯的函數隊列。type是隊列名稱,默認是fx。data參數等同於jQuery.queue中的data參數 if ( typeof type !== "string" ) { //修正參數 當傳入的格式是queue()或queue(data) (注:data能夠是函數或函數數組)時 data = type; type = "fx"; } if ( data === undefined ) { //若是沒有傳入data參數, return jQuery.queue( this[0], type ); //則調用jQuery.queue()返回第一個匹配元素上參數type對應的隊列 } return this.each(function() { //若是傳入了data參數 var queue = jQuery.queue( this, type, data ); //爲每個匹配元素調用jQuery.queue( this, type, data ),把參數(函數)入隊,或者用參數data(函數數組)替換隊列。 if ( type === "fx" && queue[0] !== "inprogress" ) { //對於動畫隊列fx,且沒有動畫函數正在執行,則當即出隊並執行動畫函數。 jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { //出隊並執行匹配元素關聯的函數隊列中的下一個函數 return this.each(function() { jQuery.dequeue( this, type ); }); }, /*略*/ })