Callback模塊是用來管理回調函數,也做爲deferred延遲對象得基礎部分,如今一塊兒來看看他的源碼。
可選參數:java
Options: once: 是否最多執行一次, memory: 是否記住最近的上下文和參數 stopOnFalse: 當某個回調函數返回false時中斷執行 unique: 相同得回調只被添加一次
這是可選參數,下面能夠進行試驗:數組
var a = function (value) { console.log('a:' + value); }; var b = function (value) { console.log('b:' + value); }; var callbacks = $.Callbacks(); callbacks.add(a); callbacks.fire(['hello']); callbacks.add(b); callbacks.fire('中');
下面是他的輸出結果:緩存
a: hello, a:中, b:中
能夠看到得是,當咱們第二次fire得時候,a函數也會執行。
在加入參數進行實驗,首先加入memoryapp
var callbacks = $.Callbacks({ memory: true }); callbacks.add(a); callbacks.fire('hello'); callbacks.add(b); 輸出: a:hello, b:hello
加入memory參數,memory記錄上一次觸發回調函數,以後添加的函數都用這參數當即執行。在來看once的使用函數
var callbacks = $.Callbacks({ once: true }); callbacks.add(a); callbacks.fire('hello'); callbacks.fire('中'); 輸出: a:hello
能夠看到的是,雖然執行了兩次fire方法,可是隻輸出了一次結果。其餘兩個參數很好理解,細節的部分本身去嘗試。this
$.Callbacks = function(options) { options = $.extend({}, options) var memory, fired, firing, firingStart, firingLength, firingIndex, list = [], stack = !options.once && [] }
再看看各個參數的意義,memory會在記憶模式下記住上一次觸發的上下文和參數,fired表明回調是否已經觸發過,firing表示回調正在觸發,firingStart回調任務開始的位置,firingLength回調任務的長度,firingIndex當前回調的索引,list表示真實的回調隊列,在不是觸發一次的狀況下,用來緩存觸發過程當中沒有執行的任務參數。code
fire = function(data) { memory = options.memory && data fired = true firingIndex = firingStart || 0 firingStart = 0 firingLength = list.length firing = true for ( ; list && firingIndex < firingLength ; ++firingIndex ) { if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) { memory = false break } } firing = false if (list) { if (stack) stack.length && fire(stack.shift()) else if (memory) list.length = 0 else Callbacks.disable() } }
fire函數是惟一內置的函數,他的做用是用於觸發list的回調執行,首先看看他傳進的參數,和我們在外部調用$.Callbacks的fire還不太同樣,這裏的data是一個數組,data[0]表示上下文,data[1]是方法調用的參數。而後就是各個參數的的初始化,memory表示若是options.memory爲true,則保存data,fired爲true,若是firingStart爲0,那麼firingIndex 爲0,firingStart置爲0,正在觸發的回調標記firing爲true。
而後遍歷回調列表,逐個執行回調,這個裏邊的if判斷表示的是若是回調函數返回的是false而且options.stopOnFalse是false,則清空memory的緩存。遍歷完成後,將執行的狀態改成false。若是list存在,stack也存在,把任務參數取出來,調用fire函數執行。若是memory存在,則清空列表,不然進行回調執行對象
最終這個文件返回的是Callbacks,咱們來看看他的具體實現:索引
Callbacks = { add: function () { if (list) { var start = list.length, add = function (args) { $.each(args, funciton(_, arg) { if (typeof arg === 'function') { if (!options.unique || !Callbacks.has(arg)) list.push(arg); } else if (arg && arg.length && typeof arg !== 'string') add(arg); }) } add(arguments) if (firing) firingLength = list.length; else if (memory) { firingStart = start; fire(memory) } } return this; } }
這個函數主要的做用就是像list裏邊push回調。首先判斷list是否存在,若是存在,start賦值爲list的長度,在內部添加一個add方法,內部add方法主要是向list添加回調,若是咱們傳入的參數是數組,就再次調用add方法。而後就是調用add方法,把arguments傳進去。若是回調正在進行,則修正回調任務的長度firingLength爲當前任務列表的長度,以便後續添加的回調函數能夠執行。若是memory存在,則把開始設置爲新添加列表的第一位,而後調用fire。
咱們再來看看fireWith的作法:隊列
fireWith: function(context, args) { if (list && (!fired || stack)) { args = args || []; args = [context, args.slice ? args.slice() : args]; if (firing) stack.push(args); else fire(args); } return this; }
傳入的參數包括上下文,和參數列表。函數執行的條件是list存在而且回調沒有執行或者stack存在,stack能夠爲空。首先對args進行從新賦值,args[0]是上下文,args[1]是複製過來的列表。若是回調正在進行,向stack裏邊添加args,或者就執行args。