前言
jQuery.Callbacks是jquery在1.7版本之後加入的,是從1.6版中的_Deferred對象中抽離的,主要用來進行函數隊列的add、remove、fire、lock等操作,並提供once、memory、unique、stopOnFalse四個option進行一些特殊的控制。
功能介紹
jq的Callbacks模塊主要是為其他模塊提供服務的,他就像一個溫柔的小女人,在背後默默地付出。Deferred就像一個巨人,在jq中那麼的突出,但在內部,他受到Callbacks的服務。
Callbacks的幾種狀態:
once -- 回調函數只執行一次
unique -- 函數不能重復添加到回調列表中
memory -- 狀態記憶,主要用於Deferred中
stopOnFalse -- 遇到return false 終止回調列表繼續執行
我自己實現的Callbacks的幾個簡單的方法
add -- 向對應的回調函數列表添加一個函數
fire -- 觸發回調,回調函數列表依次執行函數
has -- 回調函數列表是否存在傳入函數
clear -- 清空回調函數列表
整體結構
首先,我們要向得到一個想要的Callbacks模塊,需要這樣做:
var cb = Callback('memory once') // 得到一個擁有記憶功能並只執行一次的回調模塊
由於我們需要基於一定狀態來得到不同的實例,我們可以確定,我們需要一個存儲狀態的對象
var callbackState = {}
我們給Callback函數傳入了'memory once',我們怎麼記錄這兩個狀態呢,在這裡,仿jq來寫的一個函數來實現,如下:
var createCallbackState = function (options) {
var states = options.split(' ')
var obj = {}
for (var i = 0; i < states.length; i++) {
obj[states[i]] = true
}
return obj
}
以上代碼,將 'memory once' 變成了 {memory: true, once: true} ,如果狀態緩存對象裡有這個對象,直接返回,沒有的話先創建再返回。
接下來,就是Callback函數的全部代碼了,先上代碼
var Callback = function (options) {
var state = callbackState[options] //獲取狀態模式
if (!state) {
callbackState[options] = state = createCallbackState(options)
}
var list = [], // 回調函數列表
memory, // 存儲是否為 記憶狀態
has = function (fn) {
for (var i = 0; i < list.length; i++) {
if (list[i] === fn) {
return true
}
}
return false
},
add = function () {
var i = 0,
args = arguments,
len = args.length
for (; i < len; i++) {
if (state.unique && has(args[i])) { // 如果是unique狀態下並回調列表已經擁有該函數,則不添加
continue
}
list.push(args[i])
}
},
fire = function (context, args) {
var i = 0,
len = list.length,
item
for (; i < len; i++) {
item = list[i]
if (item.apply(context,args) === false && state.stopOnFalse) { //如果函數運行返回false,並且是stopOnFalse狀態,終止循環
break;
}
}
}
return {
add: function () {
add.apply(null,arguments)
// 如果memory模式並且已經擁有了memory信息,接著出發函數
if (state.memory && memory) {
fire(memory[0], memory[1])
list = []
}
},
fire: function (context, args) {
// 如果memory模式,並且list是空,代表觸發在添加前,保存memory信息
if (state.memory && !list.length) {
memory = [context, args]
return
}
fire(context,args)
if (state.once) {
this.clear()
}
},
has: function (fn) {
return has(fn)
},
clear: function () {
list = []
}
}
}
Callback函數執行後,返回一個對象,然後該對象包含了幾個簡單的功能。
下面我來介紹一下這部分的實現。
首先,如jq一樣,我也定義了內部的add, fire, has方法,主要原因是邏輯需要,在返回對象的方法中實現once,memory狀態控制,內部的add,fire方法是純粹的添加和觸發函數。
先來看cb.add方法,add方法可以接收多個函數,因此
add.apply(null,arguments)
使用內部的add做添加功能
再往下的一部分的功能是判斷這個回調模塊是否是memory狀態,理解Deferred模塊的同學應該知道,該模塊是Promise模式,訂閱成功或失敗狀態的回調函數,然後再某一時刻觸發他,這個模式便引用了memory狀態下的Callback,這個模式有一個奇怪的地方,如果你先發布成功,但是回調列表空空如也,那麼程序並不會發布失敗,而是等待成功回調函數的加入,一但回調函數加入,立刻執行他。
就是如下代碼
// 如果memory模式並且已經擁有了memory信息,立刻觸發函數
if (state.memory && memory) {
fire(memory[0], memory[1])
list = []
}
提示 : ‘如果你先發布成功,但是回調列表空空如也,那麼程序並不會發布失敗,而是等待成功回調函數的加入,一但回調函數加入,立刻執行他' 的理解如下代碼
var cb = Callback('memory') // 得到記憶功能的回調模塊
cb.fire() // 觸發回調隊列
cb.add(fn) //添加回調函數,自動執行了!
function fn () {
console.log('fn')
}
如果在非memory狀態,以上代碼無效。需要再次fire才會執行。
經過上述,fire函數也好理解了,fire可接收兩個參數,函數上下文,函數參數數組。
與add中memory狀態的代碼連串起來,以下代碼就是fire時memory狀態下的操作
// 如果memory模式,並且list是空,代表觸發在添加前,保存memory信息
if (state.memory && !list.length) {
memory = [context, args]
return
}
如果是memory狀態,回調列表為空,就保存函數執行上下文和參數數組,等add時立刻執行。
除了上述以外,代碼就很簡單易懂啦,Callback函數就到這裡了,很簡單的功能,唯一一點不好理解的就是memory狀態。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對的支持。