jQuery 源碼分析(十一) 隊列模塊 Queue詳解

隊列是經常使用的數據結構之一,只容許在表的前端(隊頭)進行刪除操做(出隊),在表的後端(隊尾)進行插入操做(入隊)。特色是先進先出,最早插入的元素最早被刪除。html

在jQuery內部,隊列模塊爲動畫模塊提供基礎功能,負責存儲動畫函數、自動出隊並執行動畫函數,同時還要確保動畫函數的順序執行。前端

jQuery的靜態方法含有以下API:jquery

  • $.queue(elem,type,data) ;返回或修改匹配元素關聯的隊列,返回最新的隊列,參數以下:

                  elem   ;DOM元素或JavaScript對象後端

                type   ;隊列名稱,默認是標準動畫fx數組

                data  ;須要設置的隊列函數,能夠是空(返回隊列)、函數(加入隊列)或函數數組(替換隊列)promise

  • $.dequeue(elem,type)   ;用於出隊並執行匹配元素關聯的函數隊列中的下一個元素

                elem  ;DOM元素或JavaScript對象緩存

                type  ;是隊列名稱,默認爲動畫隊列fx數據結構

 writer by:大沙漠 QQ:22969969函數

jQuery/$ 實例方法(能夠經過jQuery實例調用的):源碼分析

  • queue(type,data)        ;返回第一個匹配元素的函數隊列,或修改全部匹配的元素關聯的函數隊列,參數以下:

                type  ;隊列名稱

                data  ;data是可選的函數或函數數組,參數同$.queue()的第三個參數

  • dequeue(type)       ;出隊並執行全部匹配元素關聯的函數隊列中的下一個函數
  • delay(time,type)          ;延遲函數出隊執行。經過調用.queue(type,data)向關聯的函數隊列中插入一個新的函數,在函數內經過setTimeout()延遲下一個函數的出隊時間。
  • clearQueue(type)          ;移除匹配元素關聯的函數隊列中的全部未被執行的函數,內部代碼就一句:return this.queue( type || "fx", [] );

舉個栗子:

<!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 );
        });
    },
    /**/
})
相關文章
相關標籤/搜索