jquery.Callbacks的實(shí)現(xiàn)詳解
前言
jQuery.Callbacks是jquery在1.7版本之后加入的,是從1.6版中的_Deferred對(duì)象中抽離的,主要用來進(jìn)行函數(shù)隊(duì)列的add、remove、fire、lock等操作,并提供once、memory、unique、stopOnFalse四個(gè)option進(jìn)行一些特殊的控制。
功能介紹
jq的Callbacks模塊主要是為其他模塊提供服務(wù)的,他就像一個(gè)溫柔的小女人,在背后默默地付出。Deferred就像一個(gè)巨人,在jq中那么的突出,但在內(nèi)部,他受到Callbacks的服務(wù)。
Callbacks的幾種狀態(tài):
once -- 回調(diào)函數(shù)只執(zhí)行一次
unique -- 函數(shù)不能重復(fù)添加到回調(diào)列表中
memory -- 狀態(tài)記憶,主要用于Deferred中
stopOnFalse -- 遇到return false 終止回調(diào)列表繼續(xù)執(zhí)行
我自己實(shí)現(xiàn)的Callbacks的幾個(gè)簡(jiǎn)單的方法
add -- 向?qū)?yīng)的回調(diào)函數(shù)列表添加一個(gè)函數(shù)
fire -- 觸發(fā)回調(diào),回調(diào)函數(shù)列表依次執(zhí)行函數(shù)
has -- 回調(diào)函數(shù)列表是否存在傳入函數(shù)
clear -- 清空回調(diào)函數(shù)列表
整體結(jié)構(gòu)
首先,我們要向得到一個(gè)想要的Callbacks模塊,需要這樣做:
var cb = Callback('memory once') // 得到一個(gè)擁有記憶功能并只執(zhí)行一次的回調(diào)模塊
由于我們需要基于一定狀態(tài)來得到不同的實(shí)例,我們可以確定,我們需要一個(gè)存儲(chǔ)狀態(tài)的對(duì)象
var callbackState = {}
我們給Callback函數(shù)傳入了'memory once',我們?cè)趺从涗涍@兩個(gè)狀態(tài)呢,在這里,仿jq來寫的一個(gè)函數(shù)來實(shí)現(xiàn),如下:
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}
,如果狀態(tài)緩存對(duì)象里有這個(gè)對(duì)象,直接返回,沒有的話先創(chuàng)建再返回。
接下來,就是Callback函數(shù)的全部代碼了,先上代碼
var Callback = function (options) { var state = callbackState[options] //獲取狀態(tài)模式 if (!state) { callbackState[options] = state = createCallbackState(options) } var list = [], // 回調(diào)函數(shù)列表 memory, // 存儲(chǔ)是否為 記憶狀態(tài) 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狀態(tài)下并回調(diào)列表已經(jīng)擁有該函數(shù),則不添加 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) { //如果函數(shù)運(yùn)行返回false,并且是stopOnFalse狀態(tài),終止循環(huán) break; } } } return { add: function () { add.apply(null,arguments) // 如果memory模式并且已經(jīng)擁有了memory信息,接著出發(fā)函數(shù) if (state.memory && memory) { fire(memory[0], memory[1]) list = [] } }, fire: function (context, args) { // 如果memory模式,并且list是空,代表觸發(fā)在添加前,保存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函數(shù)執(zhí)行后,返回一個(gè)對(duì)象,然后該對(duì)象包含了幾個(gè)簡(jiǎn)單的功能。
下面我來介紹一下這部分的實(shí)現(xiàn)。
首先,如jq一樣,我也定義了內(nèi)部的add, fire, has方法,主要原因是邏輯需要,在返回對(duì)象的方法中實(shí)現(xiàn)once,memory狀態(tài)控制,內(nèi)部的add,fire方法是純粹的添加和觸發(fā)函數(shù)。
先來看cb.add
方法,add方法可以接收多個(gè)函數(shù),因此
add.apply(null,arguments)
使用內(nèi)部的add做添加功能
再往下的一部分的功能是判斷這個(gè)回調(diào)模塊是否是memory狀態(tài),理解Deferred模塊的同學(xué)應(yīng)該知道,該模塊是Promise模式,訂閱成功或失敗狀態(tài)的回調(diào)函數(shù),然后再某一時(shí)刻觸發(fā)他,這個(gè)模式便引用了memory狀態(tài)下的Callback,這個(gè)模式有一個(gè)奇怪的地方,如果你先發(fā)布成功,但是回調(diào)列表空空如也,那么程序并不會(huì)發(fā)布失敗,而是等待成功回調(diào)函數(shù)的加入,一但回調(diào)函數(shù)加入,立刻執(zhí)行他。
就是如下代碼
// 如果memory模式并且已經(jīng)擁有了memory信息,立刻觸發(fā)函數(shù) if (state.memory && memory) { fire(memory[0], memory[1]) list = [] }
提示 : ‘如果你先發(fā)布成功,但是回調(diào)列表空空如也,那么程序并不會(huì)發(fā)布失敗,而是等待成功回調(diào)函數(shù)的加入,一但回調(diào)函數(shù)加入,立刻執(zhí)行他' 的理解如下代碼
var cb = Callback('memory') // 得到記憶功能的回調(diào)模塊 cb.fire() // 觸發(fā)回調(diào)隊(duì)列 cb.add(fn) //添加回調(diào)函數(shù),自動(dòng)執(zhí)行了! function fn () { console.log('fn') }
如果在非memory狀態(tài),以上代碼無效。需要再次fire才會(huì)執(zhí)行。
經(jīng)過上述,fire函數(shù)也好理解了,fire可接收兩個(gè)參數(shù),函數(shù)上下文,函數(shù)參數(shù)數(shù)組。
與add中memory狀態(tài)的代碼連串起來,以下代碼就是fire時(shí)memory狀態(tài)下的操作
// 如果memory模式,并且list是空,代表觸發(fā)在添加前,保存memory信息 if (state.memory && !list.length) { memory = [context, args] return }
如果是memory狀態(tài),回調(diào)列表為空,就保存函數(shù)執(zhí)行上下文和參數(shù)數(shù)組,等add時(shí)立刻執(zhí)行。
除了上述以外,代碼就很簡(jiǎn)單易懂啦,Callback函數(shù)就到這里了,很簡(jiǎn)單的功能,唯一一點(diǎn)不好理解的就是memory狀態(tài)。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- 自己動(dòng)手實(shí)現(xiàn)jQuery Callbacks完整功能代碼詳解
- jQuery源碼分析之Callbacks詳解
- jQuery.Callbacks()回調(diào)函數(shù)隊(duì)列用法詳解
- jQuery回調(diào)函數(shù)的定義及用法實(shí)例
- 使用jQuery中的when實(shí)現(xiàn)多個(gè)AJAX請(qǐng)求對(duì)應(yīng)單個(gè)回調(diào)的例子分享
- jQuery Tips 為AJAX回調(diào)函數(shù)傳遞額外參數(shù)的方法
- Jquery版本導(dǎo)致Ajax不執(zhí)行success回調(diào)函數(shù)
- jQuery AJAX回調(diào)函數(shù)this指向問題
- Jquery Post處理后不進(jìn)入回調(diào)的原因及解決方法
- 從零學(xué)jquery之如何使用回調(diào)函數(shù)
相關(guān)文章
動(dòng)態(tài)生成的DOM不會(huì)觸發(fā)onclick事件的原因及解決方法
下面小編就為大家?guī)硪黄獎(jiǎng)討B(tài)生成的DOM不會(huì)觸發(fā)onclick事件的原因及解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-08-08jQuery實(shí)現(xiàn)圖片放大預(yù)覽實(shí)現(xiàn)原理及代碼
jQuery實(shí)現(xiàn)圖片放大原理很簡(jiǎn)單,就是將圖片顯示的尺寸變大后放在瀏覽器的一個(gè)指定位置,從而實(shí)現(xiàn)圖片的放大預(yù)覽,下面有個(gè)不錯(cuò)的示例,感興趣的朋友可以參考下2013-09-09jQuery+ajax實(shí)現(xiàn)動(dòng)態(tài)執(zhí)行腳本的方法
這篇文章主要介紹了jQuery+ajax實(shí)現(xiàn)動(dòng)態(tài)執(zhí)行腳本的方法,分析了jQuery+Ajax實(shí)現(xiàn)腳本的動(dòng)態(tài)加載與執(zhí)行的技巧,需要的朋友可以參考下2015-01-01jQuery延遲執(zhí)行的實(shí)現(xiàn)方法
這篇文章主要介紹了jQuery延遲執(zhí)行的實(shí)現(xiàn)方法,結(jié)合簡(jiǎn)單實(shí)例形式分析了jQuery針對(duì)無法同步執(zhí)行的情況使用延遲執(zhí)行的操作技巧,需要的朋友可以參考下2016-12-12js實(shí)現(xiàn)的黑背景灰色二級(jí)導(dǎo)航菜單效果代碼
這篇文章主要介紹了js實(shí)現(xiàn)的黑背景灰色二級(jí)導(dǎo)航菜單效果代碼,涉及javascript操作頁面元素動(dòng)態(tài)切換的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-08-08jQuery實(shí)現(xiàn)圖片與文字描述左右滑動(dòng)自動(dòng)切換的方法
這篇文章主要介紹了jQuery實(shí)現(xiàn)圖片與文字描述左右滑動(dòng)自動(dòng)切換的方法,涉及jquery實(shí)現(xiàn)圖文滑動(dòng)切換效果的方法,涉及jquery針對(duì)頁面元素與樣式的相關(guān)操作技巧,需要的朋友可以參考下2015-07-07jQuery扁平化風(fēng)格下拉框美化插件FancySelect使用指南
這篇文章主要介紹了jQuery扁平化風(fēng)格下拉框美化插件FancySelect使用指南,需要的朋友可以參考下2015-02-02jQuery 數(shù)據(jù)緩存data(name, value)詳解及實(shí)現(xiàn)
本文要討論的是最流行的JavaScript框架jQuery的數(shù)據(jù)緩存實(shí)現(xiàn)原理,這是jQuery1.2.3版開始加入的新功能。2010-01-01