zepto源碼Callback

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。

相關文章
相關標籤/搜索