Zepto源碼之callback模塊

整體結構

;(function($){
    $.Callbacks = function(options) {
        Callbacks = {
            // code
        }
        return Callbacks
    }
})(Zepto)

從整體上來看,我們可以看到,其實就是向 Zepto 對象上添加了一個 Callbacks 的工廠函數。工廠函數返回一個對象。

代碼詳解


;(function($){
  $.Callbacks = function(options) {
    options = $.extend({}, options)

    var memory, fired, firing, firingStart, firingLength, firingIndex, list = [], stack = !options.once && []

    // 這是 Callbacks 模塊唯一的內部方法,主要是用於觸發回調的執行
    var fire = function(data) {
          memory = options.memory && data
          fired = true
          firingIndex = firingStart || 0
          firingStart = 0
          firingLength = list.length
          firing = true
          // 遍歷回調列表,逐個執行回調
          // 當回調列表存在且執行回調任務的索引值要小於執行列表的長度的時候執行
          for ( ; list && firingIndex < firingLength ; ++firingIndex ) {
            // 使用 apply 傳入對應的上下文對象與參數,如果返回 false ,並且 options.stopOnFalse 爲 true,那麼清空緩存,跳出循環,不再向下執行
            if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) {
              memory = false
              break
            }
          }
          // 設置標記,表示沒有正在執行的任務了
          firing = false

          if (list) {
            // 檢查 stack 列表,看看基本是否有未完成任務,如果有,那麼執行 
            if (stack) stack.length && fire(stack.shift())
            else if (memory) list.length = 0
            else Callbacks.disable()
          }
        },

        Callbacks = {
          add: function() {
            if (list) {
              var start = list.length,
                  // 添加一個 add 的內部方法,其主要用處是處理參數,將其正確的 push 進 list 列表中
                  add = function(args) {
                    $.each(args, function(_, arg){
                      // 如果傳入參數爲 function ,且 options 設置中 unique 爲負或者 在回調列表中不存在,那麼直接 push 進 list 列表
                      if (typeof arg === "function") {
                        if (!options.unique || !Callbacks.has(arg)) list.push(arg)
                      }
                      // 在類數組情況下,遞歸分解
                      else if (arg && arg.length && typeof arg !== 'string') add(arg)
                    })
                  }
              // 調用內部方法 add 處理參數
              add(arguments)
              // 如果回調正在執行中,修正任務列表長度
              if (firing) firingLength = list.length
              else if (memory) {
                // 如果是 memory 模式,立即執行新添加的回調,再繼續執行
                firingStart = start
                fire(memory)
              }
            }
            return this
          },
          // 刪除列表中指定的回調
          remove: function() {
            if (list) {
              $.each(arguments, function(_, arg){
                var index
                // 當指定參數在待執行列表中
                while ((index = $.inArray(arg, list, index)) > -1) {
                  // 刪除待執行的回調
                  list.splice(index, 1)
                  // 如果正在執行
                  if (firing) {
                    // 修正處理參數
                    if (index <= firingLength) --firingLength
                    if (index <= firingIndex) --firingIndex
                  }
                }
              })
            }
            return this
          },
          // 檢查回調是不是在待執行列表中
          has: function(fn) {
            return !!(list && (fn ? $.inArray(fn, list) > -1 : list.length))
          },
          // 清空執行回調列表
          empty: function() {
            firingLength = list.length = 0
            return this
          },
          // 禁用回調
          disable: function() {
            list = stack = memory = undefined
            return this
          },
          // 檢查回調禁用狀態
          disabled: function() {
            return !list
          },
          // 鎖定回調列表,不添加新的回調
          lock: function() {
            stack = undefined
            if (!memory) Callbacks.disable()
            return this
          },
          // 檢查鎖定狀態
          locked: function() {
            return !stack
          },
          // 用指定上下文來執行回調函數,兩個參數,第一個是上下文對象,第二個是執行參數列表
          fireWith: function(context, args) {
            if (list && (!fired || stack)) {
            // 回調待執行列表存在且未執行過或者 stack 存在
              // 如果args存在就不修改,否則賦值爲空數組
              args = args || []
              // 重組 args 使其成爲 list 所需要的參數形式
              args = [context, args.slice ? args.slice() : args]
              // 如果回調正在執行中,那麼 push 進 stack 列表
              if (firing) stack.push(args)
              // 否則執行
              else fire(args)
            }
            return this
          },
          // 用當前上下文來執行回調函數
          fire: function() {
            return Callbacks.fireWith(this, arguments)
          },
          // 檢測回調是否正在執行
          fired: function() {
            return !!fired
          }
        }

    return Callbacks
  }
})(Zepto)
發佈了88 篇原創文章 · 獲贊 41 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章