jquery Callbacks 回調對象的讀書筆記-源碼分析

Callbacks:回調對象,函數的一個統一管理(觀察者模式)

基本使用

function test1() {
    console.log("test1 ...");
}
function test2() {
    console.log("test2 ...");
}
var cb = $.Callbacks();
cb.add(test1);
cb.add(test2);
cb.fire();

結果:json

test1 ...數組

test2 ...緩存

 

基本用處

1.對不一樣做用域的函數進行統一的管理app

2.簡化統一調用函數

看下面的例子:this

var cb = $.Callbacks();//聲明一個全局的回調對象
function test1() {
    console.log("test1 ...");
}
cb.add(test1);
(function () {
    function test2() {//test2爲局部函數,外層中不能調用
        console.log("test2 ...");
    }
    cb.add(test2);
})();
cb.fire()//簡化了調用方式

結果:spa

test1 ...對象

test2 ...遞歸

 

Callbacks(options)參數

參數說明:索引

1.once:使回調函數只能被調用一次,如:

cb.fire();

cb.fire();//第二次調用回調函數將無效

2.memory:無視添加回調函數的順序,如:

cb.add(test1);

cb.fire();//test1/test2都將會執行

cb.add(test2);

3.unique:去除重複的回調函數,如:

cb.add(test1);

cb.add(test1);

cb.fire();//test1只會調用一次

4.stopOnFalse:當添加的回調函數有返回false時,後續的回調函數將不執行

cb.add(test1);//假設test1()爲return false

cb.add(test2);

cb.fire();//將只會執行到test1,test2不會執行

5.此外,Callbacks還支持多個參數共同傳遞,如Callbacks('memory once')

參數處理:

var optionsCache = {};//options的緩存對象
function createOptions( options ) {
    var object = optionsCache[ options ] = {};
    jQuery.each(//遍歷options數組,進行處理
        options.match( core_rnotwhite ) || [],//對options進行空格的切分
        function( _, flag ) {
             object[ flag ] = true;//對單個option進行存放
         }
    );
    return object;
}
options =
    typeof options === "string" ?//判斷options是字符串
    ( optionsCache[ options ]//讀取緩存options
    || createOptions( options )//建立緩存對象
    ) :
    jQuery.extend( {}, options );//options爲空時,合併類數組,防止出現undefined

Callbacks('memory once')

1.options的狀況:createOptions( options )返回的是{once:true, memory:true}

2.optionsCache的狀況:optionsCache的值爲{'once memory':{once:true, memory:true}}

3.options從新賦值:先根據options取optionsCache的值,爲空則建立一個options

 

js中的默認的true與false:

1.false狀況:false null undefined 0 '' NaN

2.true狀況:包括對象、數組、正則、函數等。注意 '0'、'null'、'false'、{}、[]也都是true

3.未定義的變量直接判斷true/false程序報錯

 

Callbacks的私有成員

私有變量:

1.memeroy:最後一次觸發回調時傳的參數

2.fired:列表中的函數是否已經回調至少一次

3.firing:列表中的回調函數是否正在被回調中

4.firingStart:回調的起點

5.firingLength:須要fire的隊列長度

6.firingIndex:當前正在firing的回調的隊列的索引

7.list:[],定義回調函數列表

8.stack:!options.once&&[],當options有once屬性時stack爲[](主要用來保存當前正在執行回調函數時的函數,),不然爲true

私有方法:在這裏真正執行須要回調的函數

fire = function( data ) {//data= [context, [arg1, arg2, arg3, ...]],context=this
    memory = options.memory && data;//判斷options是否有memory參數,無爲undefined,不然爲data
    fired = true;
    firingIndex = firingStart || 0;//賦值firingIndex
    firingStart = 0;//初始爲0
    firingLength = list.length;//回調列表長度
    firing = true;//true表示回調函數正在執行
    for ( ; list && firingIndex < firingLength; firingIndex++ ) {//遍歷回調列表
        // data[ 0 ]是函數執行的上下文,也就是平時的this
        // 這裏看再看下 self.fireWith 傳過來的參數 args 的格式
        // 若是是stopOnFalse管理器,而且回調返回值是false,中斷!
        // list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) 是最終的執行回調的方法
        if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {//options中的stopOnFalse在這做用,執行帶有false的回調函數而且有stopOnFalse參數,break出循環
            memory = false; // To prevent further calls using add
            break;
        }
    }
    firing = false;
    if ( list ) {
        if ( stack ) {
            if ( stack.length ) {
                fire( stack.shift() );
            }
        } else if ( memory ) {//options爲stopOnFalse和memory的狀況
            list = [];
        } else {
            self.disable();
        }
    }
},

 

Callbacks的公有成員

注意:建立Callbacks返回的是self,而self是一個json,存放Callbacks的公有方法

公有方法

1.add

// Actual callback list
list = [],//回調函數列表
add: function() {
    if ( list ) {//list爲空是,爲ture
        // First, we save the current length
        var start = list.length;//保存回調函數列表的長度
        (function add( args ) {//add自執行函數
            jQuery.each( args, function( _, arg ) {//遍歷參數,args=arguments
                var type = jQuery.type( arg );//判斷參數的類型
                if ( type === "function" ) {
                    if ( !options.unique || !self.has( arg ) ) {//options中的unique在這做用,判斷建立Callbacks是否有unique,取反,後判斷回調函數是否在回調列表中
                        //1.options.unique爲true,則爲false,arg在list爲true,反爲false,不push進list中,反之
                        //2.options.unique爲undefined ,則爲true,不判斷唯一性,直接push
                        list.push( arg );
                    }
                } else if ( arg && arg.length && type !== "string" ) {//cb.add([test2,test1])這種狀況
                    // Inspect recursively
                    add( arg );//進行遞歸調用
                }
            });
        })( arguments );//將arguments傳進add
        // Do we need to add the callbacks to the
        // current firing batch?
        if ( firing ) {//若是當前在 firing 當中,那就把須要firing的長度設置成列表長度
            firingLength = list.length;
            // With memory, if we're not firing then
            // we should call right away
        } else if ( memory ) {//options中的memory在這做用,add後在次調用了fire
            //初始memory爲空,則爲false,當進行一次fire後,memory判斷爲true,調用fire,執行回調函數
            firingStart = start;
            fire( memory );
        }
    }
    return this;
},

3.fire():執行回調列表中的回調方法,調用了另外一個公有方法,並傳遞this和參數列表

fire: function() {//調用回調函數
    self.fireWith( this, arguments );//支持cb.fire('hello');
    return this;
},

4.fireWith():帶有參數的調用私有的fire()

// 以給定的上下文和參數調用全部回調函數
fireWith: function( context, args ) {
    if ( list && ( !fired || stack ) ) {//options中的once在這做用,有once時,stack爲false,當fire一次後,fired爲true,因此第二次fire不執行
        args = args || [];
        args = [ context, args.slice ? args.slice() : args ];  // 把 args 組織成 [context, [arg1, arg2, arg3, ...]]
        // function aaa() {
        //     console.log(111)
        //     cb.fire();
        // }
        // function bbb() {
        //     console.log(222)
        // }
        // var cb = $.Callbacks();
        // cb.add(aaa);
        // cb.add(bbb);
        // cb.fire();這種狀況
        if ( firing ) {// 若是當前還在 firing,
            stack.push( args ); // 將參數推入堆棧,等待當前回調結束再調用
        } else {
            fire( args );//args包含this和arguments
        }
    }
    return this;
},

5.empty()

empty: function() {//清空回調列表
    list = [];
    firingLength = 0;
    return this;
},

6.disable()

// 禁用回調列表中的回調
// 禁用掉以後,把裏邊的隊列、棧等所有清空了!沒法再恢復了,再次調用fire()無效
disable: function() {
    list = stack = memory = undefined;
    return this;
},

7.disabled():判斷是否禁止,當調用disable()後,list爲undefined,取反

disabled: function() {
    return !list;
},

8.lock()

lock: function() {//鎖住數組,禁止第二次fire(),
    stack = undefined;//清空棧,fire()一次後fired=true,fireWith()中( !fired || stack ) 爲false
    if ( !memory ) {
        self.disable();
    }
    return this;
},

9.locked():lock後stack爲undefined,取反,當options中有once參數,後續lock操做沒意義

locked: function() {//list是否被鎖住,返回一個鎖標誌
    return !stack;
},

10.remove():刪除回調列表,支持多個回調函數一塊兒刪除

remove: function() {//刪除回調列表
    if ( list ) {
        jQuery.each( arguments, function( _, arg ) {//遍歷參數列表
            var index;
            while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                // splice(index,howmany) 方法向/從數組中添加/刪除項目,而後返回被刪除的項目
                // index -- 必需。整數,規定添加/刪除項目的位置
                // howmany -- 必需。要刪除的項目數量。若是設置爲 0,則不會刪除項目
                // 從回調隊列中移除當前查找到的這個方法
                list.splice( index, 1 );
                // Handle firing indexes
                // 在函數列表處於firing狀態時,最主要的就是維護firingLength和firgingIndex這兩個值
                // 保證fire時函數列表中的函數可以被正確執行,防止取到(fire中的for循環須要這兩個值
                // function aaa() {
                //     console.log(1);
                //     cb.remove(bbb);
                // }
                if ( firing ) {
                    if ( index <= firingLength ) {
                        firingLength--;
                    }
                    if ( index <= firingIndex ) {
                        firingIndex--;
                    }
                }
            }
        });
    }
    return this;
},
相關文章
相關標籤/搜索