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

来源:https://www.cnblogs.com/greatdesert/archive/2019/10/16/11670591.html
-Advertisement-
Play Games

隊列是常用的數據結構之一,只允許在表的前端(隊頭)進行刪除操作(出隊),在表的後端(隊尾)進行插入操作(入隊)。特點是先進先出,最先插入的元素最先被刪除。 在jQuery內部,隊列模塊為動畫模塊提供基礎功能,負責存儲動畫函數、自動出隊並執行動畫函數,同時還要確保動畫函數的順序執行。 jQuery的靜 ...


隊列是常用的數據結構之一,只允許在表的前端(隊頭)進行刪除操作(出隊),在表的後端(隊尾)進行插入操作(入隊)。特點是先進先出,最先插入的元素最先被刪除。

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

jQuery的靜態方法含有如下API:

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

                  elem   ;DOM元素或JavaScript對象

                type   ;隊列名稱,預設是標準動畫fx

                data  ;需要設置的隊列函數,可以是空(返回隊列)、函數(加入隊列)或函數數組(替換隊列)

  • $.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 );
        });
    },
    /**/
})

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 概述 數據完整性指資料庫中數據的 正確性、相容性和一致性 。包括現實世界中的應用需求的完整性。數據的完整性由完整性規則來定義。 關係模型的完整性規則是對關係的某種約束,提供一種手段來保證用戶對資料庫的修改時不會破壞資料庫中數據的完整性。保證數據是有意義的。 關係模型分三類約束:實體完整性約束、參照完 ...
  • 在SQL Server中重建索引(Rebuild Index)與重組索引(Reorganize Index)會觸發統計信息更新嗎? 那麼我們先來測試、驗證一下: 我們以AdventureWorks2014為測試環境,如下所示: Person.Person表的統計信息最後一次更新為2014-07-17... ...
  • 本文基於 Android 9.0 , 代碼倉庫地址 : "android_9.0.0_r45" 文中源碼鏈接: "SystemServer.java" "ActivityManagerService.java" "Process.java" "ZygoteProcess.java" 對 和 啟動流程 ...
  • 1. 在對象內部讀取數據時,應該直接通過實例變數來讀,而寫入數據時,則應通過屬性來寫。 2. 在初始化方法及dealloc方法中,總是應該直接通過實例變數來讀寫數據。 3. 使用Lazy Initialization配置的數據,應該通過屬性來讀取數據。 4. 不要在setter/g... ...
  • 1. 可以用@property語法來定義對象中所封裝的數據。 2. 通過“修飾詞”來指定存儲數據所需的正確語義。 3. 在設置屬性所對應的實例變數時,一定要遵從該屬性所聲明的語義。 4. 開發iOS程式時應該使用nonatomic屬性,因為atomic(同步鎖)屬性嚴重影響性能。 ...
  • 1. 應該用枚舉表示狀態機的狀態、傳遞給方法的選項以及狀態碼等值,給這些值起個易懂的名字,就像監聽網路狀態的枚舉。 2. 如果把傳遞給某個方法的選項表示為枚舉類型,而多個選項又可同時使用,那麼就將各選項定義為2的冪,以便通過按位或操作將其組合起來。 3. 用 NS_ENUM 與 NS_O... ...
  • 本篇記錄的是使用Jsoup框架爬取網頁內容,結合Android的RecyclerView,從而實現批量下載小說的功能(也是我的APP "星之小說下載器Android版" 的核心功能), 思路僅供參考 本文使用了AsyncTask來實現下載功能,不懂使用的可以參考一下我的文章 "Android開發—— ...
  • 換膚思路: 1.什麼時候換膚? xml載入前換膚,如果xml載入後換膚,用戶將會看見換膚之前的色彩,用戶體驗不好。 2.皮膚是什麼? 皮膚就是apk,是一個資源包,包含了顏色、圖片等。 3.什麼樣的控制項應該進行換膚? 包含背景圖片的控制項,例如textView文字顏色。 4.皮膚與已安裝的資源如何匹配 ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...