首頁 >web前端 >js教程 >jQuery源碼之Callbacks的學習

jQuery源碼之Callbacks的學習

不言
不言原創
2018-07-09 10:57:341371瀏覽

這篇文章主要介紹了關於jQuery源碼之Callbacks的學習,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

jQuery源碼學習之Callbacks

jQuery的ajaxdeferred透過回呼實現非同步,其實作核心是Callbacks

使用方法

使用首先要先新建一個實例物件。建立時可以傳入參數flags,表示對回呼物件的限制,可選值如下表示。

  • stopOnFalse:回呼函數佇列中的函數返回false時停止觸發

  • ##once
:回呼函數佇列只能被觸發一次

    memory
  • :記錄上一次觸發佇列傳入的值,並新加入到佇列中的函數使用記錄值作為參數,並立即執行。

  • unique
  • :函數佇列中函數都是唯一的

    var cb = $.Callbacks('memory');
    cb.add(function(val){
        console.log('1: ' + val)
    })
    cb.fire('callback')
    cb.add(function(val){
        console.log('2: ' + val)
    })
    // console输出
    1: callback
    2: callback

  • Callbacks
  • 提供了一系列實例方法來操作佇列和查看回呼物件的狀態。

  • add
  • : 新增函數到回呼佇列中,可以是函數或函數陣列

  • #remove
  • : 從回呼佇列中刪除指定函數

  • has
  • : 判斷回呼佇列裡是否存在某個函數

  • empty
  • : 清空回呼佇列

    disable

    : 禁止新增函數和觸發佇列,清空回呼佇列和上一個傳入的值
  • disabled: 判斷回呼物件是否被停用

  • lock: 停用fire ,若memory非空則同時add無效

  • locked: 判斷是否呼叫了lock

fireWith

: 傳入

context和參數,觸發隊列##fire: 傳入參數觸發對象,context是回呼對象

原始碼解析$.Callback()方法內部定義了多個局部變數和方法,用於記錄回調物件的狀態和函數佇列等,傳回self,在self實現了上述回呼物件的方法,使用者只能透過self 提供的方法來更改回呼物件。這樣的好處是保證除了self之外,沒有其他修改回呼物件的狀態和佇列的途徑。 其中,firingIndex為目前觸發函數在佇列中的索引,list是回呼函數佇列,memory記錄上次觸發的參數,當回呼物件實例化時傳入

memory

時會用到,queue儲存各個callback執行時的context和傳入的參數。 self.fire(args)實際上是self.fireWith(this,args)self.fireWith內部則呼叫了在Callbacks定義的局部函數fire<pre class="brush:php;toolbar:false">    ...     // 以下变量和函数 外部无法修改,只能通过self暴露的方法去修改和访问     var // Flag to know if list is currently firing         firing,         // Last fire value for non-forgettable lists         // 保存上一次触发callback的参数,调用add之后并用该参数触发         memory,         // Flag to know if list was already fired         fired,         // Flag to prevent firing         // locked==true fire无效 若memory非空则同时add无效         locked,         // Actual callback list         // callback函数数组         list = [],         // Queue of execution data for repeatable lists         // 保存各个callback执行时的context和传入的参数         queue = [],         // Index of currently firing callback (modified by add/remove as needed)         // 当前正触发callback的索引         firingIndex = -1,         // Fire callbacks         fire = function() {             ...         },                  // Actual Callbacks object         self = {             // Add a callback or a collection of callbacks to the list             add: function() {                 ...             },             ...             // Call all callbacks with the given context and arguments             fireWith: function( context, args ) {                 if ( !locked ) {                     args = args || [];                     args = [ context, args.slice ? args.slice() : args ]; // :前为args是数组,:后是string                     queue.push( args );                     if ( !firing ) {                         fire();                     }                 }                 return this;             },             // Call all the callbacks with the given arguments             fire: function() {                 self.fireWith( this, arguments );                 return this;             },             ...         }</pre>透過

self.add

新增函數到回呼佇列中,程式碼如下。先判斷是否memory且非正在觸發,如果是則將fireIndex移到回呼佇列的結尾,並儲存memory。接著使用立即執行函數表達式實現add函數,在該函數內遍歷傳入的參數,進行類型判斷後決定是否添加到隊列中,如果回調對像有unique標誌,則還要判斷該函數在隊列中是否已存在。如果回呼物件有memory標誌,新增完畢之後還會觸發fire,執行新新增的函數。 <pre class="brush:php;toolbar:false">            add: function() {                 if ( list ) {                     // If we have memory from a past run, we should fire after adding                     // 如果memory非空且非正在触发,在queue中保存memory的值,说明add后要执行fire                     // 将firingIndex移至list末尾 下一次fire从新add进来的函数开始                     if ( memory &amp;&amp; !firing ) {                         firingIndex = list.length - 1;                         queue.push( memory );                     }                     ( function add( args ) {                         jQuery.each( args, function( _, arg ) {                             // 传参方式为add(fn)或add(fn1,fn2)                             if ( jQuery.isFunction( arg ) ) {                                 /**                                  * options.unique==false                                  * 或                                  * options.unique==true&amp;&amp;self中没有arg                                  */                                 if ( !options.unique || !self.has( arg ) ) {                                     list.push( arg );                                 }                             } else if ( arg &amp;&amp; arg.length &amp;&amp; jQuery.type( arg ) !== &quot;string&quot; ) {                                 // 传参方式为add([fn...]) 递归                                 // Inspect recursively                                 add( arg );                             }                         } );                     } )( arguments ); //arguments为参数数组 所以add的第一步是each遍历                     //添加到list后若memory真则fire,此时firingIndex为回调队列的最后一个函数                     if ( memory &amp;&amp; !firing ) {                         fire();                     }                 }                 return this;             }</pre>firefireWith方法內部實際呼叫了局部函數fire,其程式碼如下。觸發時,需要更新firedfiring,表示已觸發和正在觸發。透過for迴圈執行隊裡中的函數。結束循環後,將

firingIndex

更新為-1,表示下次觸發從佇列中的第一個函數開始。遍歷在

fireWith

中更新過的

queue

queue

是保存數組的數組,每個數組的第一個元素是context# ,第二個元素是參數數組。執行函數時要是否回傳
false

且回呼物件有
// Fire callbacks
        fire = function() {

            // Enforce single-firing
            // 执行单次触发
            locked = locked || options.once;

            // Execute callbacks for all pending executions,
            // respecting firingIndex overrides and runtime changes
            // 标记已触发和正在触发
            fired = firing = true;
            // 循环调用list中的回调函数
            // 循环结束之后 firingIndex赋-1 下一次fire从list的第一个开始 除非firingIndex被修改过
            // 若设置了memory,add的时候会修改firingIndex并调用fire
            // queue在fireWith函数内被更新,保存了触发函数的context和参数
            for ( ; queue.length; firingIndex = -1 ) {
                memory = queue.shift();
                while ( ++firingIndex < list.length ) { 

                    // Run callback and check for early termination
                    // memory[0]是content memory[1]是参数
                    if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
                        options.stopOnFalse ) {
                        
                        // Jump to end and forget the data so .add doesn't re-fire
                        // 当前执行函数范围false且options.stopOnFalse==true 直接跳至list尾 终止循环
                        firingIndex = list.length;
                        memory = false;
                    }
                }
            }

            // 没设置memory时不保留参数
            // 设置了memory时 参数仍保留在其中
            // Forget the data if we're done with it
            if ( !options.memory ) {
                memory = false;
            }

            firing = false;

            // Clean up if we're done firing for good
            if ( locked ) {

                // Keep an empty list if we have data for future add calls
                if ( memory ) {
                    list = [];

                // Otherwise, this object is spent
                } else {
                    list = "";
                }
            }
        },

  ###以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP中文網! ######相關推薦:#########js 非同步for循環的介紹################jQuery-Ajax請求Json資料並載入在前端頁面##########

以上是jQuery源碼之Callbacks的學習的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn