本文執行個體講述了jQuery.Callbacks()回呼函數隊列用法。分享給大家供大家參考,具體如下:
1、jQuery.Callbacks
The jQuery.Callbacks() function, introduced in version 1.7, returns a multi-purpose object that provides a powerful way to manage callback lists. It supports adding, removing, firing, and disabling callbacks.
The $.Callbacks() function is internally used to provide the base functionality behind the jQuery $.ajax() and $.Deferred() components. It can be used as a similar base to define functionality for new components.
接下來,我們分別看下四個標準的控制標誌。
1.1 once
建立的 callbacks 對象只允許被 fireWith() 一次 [注意:方法fire() 是 fireWith() 的面板模式]。
var callbacks = $.Callbacks("once");callbacks.add(function(){console.log("f1");});callbacks.fire(); //輸出 "f1"callbacks.fire(); //什麼也不發生,在源碼中已經禁用了 list.disable()
1.2 memory
在調用 add() 方法時,如果這時 callbacks隊列 滿足 fired && firing = false(真執行完畢) && memory(需要在建構函式指定),那麼add() 進去的回呼函數會立即執行,而這個 add 進去的回呼函數調用時的參數儲存在 memory 變數中。memory 變數用於儲存最後一次調用 callbacks.fireWith(...) 時所使用的參數 [context, arguments]。
If the Callbacks object is created with the "memory" flag as its argument, additional functions may be added and fired after the callback list is locked.
$(function($){ var callbacks = $.Callbacks("memory"); callbacks.add(function(){console.log("f1");}); callbacks.fire(); //輸出 "f1",這時函數列表已經執行完畢! callbacks.add(function(){console.log("f2");}); //memory作用在這裡,沒有fire,一樣有結果: f2 callbacks.fire(); //重新觸發一次,輸出 f1 f2。 firingStart = 0 //與once一起使用 callbacks = $.Callbacks("once memory"); callbacks.add(function(){console.log("f3");}); callbacks.fire(); //輸出 "f3",這時函數列表已經執行完畢! callbacks.add(function(){console.log("f4");}); //沒有fire,一樣有結果: f4 callbacks.fire(); //由於為"once",這裡將什麼也不執行});
1.3 unique
回呼函數列表中的函數是否可以重複,該特性與 add() 方法有關,可以避免在回呼函數列表中加入多個相同回呼函數。
var f1 = function(){console.log("f1");};var callbacks = $.Callbacks();callbacks.add(f1);callbacks.add(f1);callbacks.fire(); //輸出 f1 f1//傳遞參數 "unique"callbacks = $.Callbacks("unique");callbacks.add(f1); //有效callbacks.add(f1); //添加不進去callbacks.fire(); //輸出: f1
1.4 stopOnFalse
預設情況下,當執行 fireWith() 方法時,整個回呼函數列表中的所有函數都會順序執行,但如果設定了stopOnFalse,那麼當某個函數返回false時,後邊的函數將不再執行。即使設定了memory,再次添加的函數也不會執行了,即一旦某個函數返回 false 的情況下,會禁用 memory 功能。但如果沒設定”once”,再次調用fire可以重新觸發該callbacks。
var f1 = function(){console.log("f1"); return false}; //注意 return false;var f2 = function(){console.log("f2");};var callbacks = $.Callbacks();callbacks.add(f1);callbacks.add(f2);callbacks.fire(); //輸出 f1 f2callbacks = $.Callbacks("memory stopOnFalse");callbacks.add(f1);callbacks.add(f2);callbacks.fire(); //只輸出 f1callbacks.add(function(){console.log("f3");}); //不會輸出,memory已經失去作用了callbacks.fire(); //重新觸發,輸出f1
2. memory 回調隊列
var i = 0;var inc = function (s){ i++; alert(i +"$" + s);};var callbacks = $.Callbacks('memory');callbacks.add(function iteral() { callbacks.add(inc); if (i <= 1) { callbacks.fire(i); }});callbacks.fire(i);callbacks.add(inc);/*list = [];list = [it];--->fire(0), i=01、list = [it, inc]2、push(fire(0))3、i++ [inc(0)] (i=1)shift()--->fire(0), i=11、list = [it, inc, inc];2、push(fire(1)),3、i++ [inc(0)]4、i++ [inc(0)] (i=3)shift()--->fire(1),i=31、list = [it, inc, inc, inc];2、i++ [inc(1)]3、i++ [inc(1)]4、i++ [inc(1)] (i=6)--->add(inc), i=6, memory=[this,1]1、i++ [inc(1)] (i=7)*/
3、 jQuery.CallBacks 源碼
說明:為了便於理解,修改了部分源碼,減少了一些功能~~~
jQuery.Callbacks = function (options) { // string --> object 改進建議:將未配置的參數預設為false,而不是undefined。便於程式閱讀和控制. options = optionsCache[options] || createOptions(options); var firing, memory, //Last fire value [context, args] (for memory lists) fired, firingLength, firingIndex, firingStart, list = [], stack = options.once === true ? false : [], // Stack of fire calls for repeatable lists fire = function (data) { // data --> [context, args] memory = !!options.memory && data; // false OR [context, arguments] fired = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; firing = true; // 這裡 list 放在條件判斷中是因為執行回呼函數可能會改變 list 的狀態,比如 this.disable()。 for ( ; list && firingIndex < firingLength; firingIndex++) { if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse === true) { memory = false; // 禁止 memory 功能,這樣調用 add() 增加新回呼函數不會立即自動調用 break; } } firing = false; if (list) { if (stack) { //進入條件: fired && firing === false && stack, 實現遞迴調用 if (stack.length) { fire(stack.shift()); // [[context1, arguments1], [context2, arguments2]] } } else if (memory) { // 進入條件: fired && firing === false && stack === undefined && 有memory欄位(memory變數只能通過fire()函數修改) // 這裡的 list = [],主要是用於效能最佳化,以防該對象長時間不執行,佔用系統記憶體 list = []; } else { // 進入條件: fired && firing === false && stack === undefined && 沒有memory欄位, 說明必要繼續保留的必要 self.disable(); } } }, self = { add: function() { if (list) { //幾乎所有API都應該綁定這個條件,因為我們需要處理隊列 var originLength = list.length; jQuery.each(arguments, function( _, arg) { if (jQuery.type(arg) === "function") { // (!(options.unique && self.has(arg))) unique欄位的作用 if (!options.unique || !self.has(arg)) { list.push(arg); } } }); if (firing === true) { // 進入條件: 說明正在執行回呼函數隊列中,而當前執行的這個回呼函數啟用了add()函數,及時維護迴圈邊界 firingLength = list.length; } else if (memory) { // 進入條件: memory && fired && firing === false, 說明之前的 fire() 行為已經完全結束 firingStart = originLength; fire(memory); } } return this; }, remove: function() { if (list) { jQuery.each(arguments, function( _, arg) { var lastIndex; while ((lastIndex = jQuery.inArray(arg, list, lastIndex)) >= 0) { list.splice(lastIndex, 1); if (firing === true) { // 及時更新邊界條件,實現智能處理 if (lastIndex <= firingLength) { firingLength--; } if (lastIndex <= firingIndex) { firingIndex--; } } } }); } return this; }, has: function (func) { //這個API有兩個功能,根據單一職責角度來說,應該增加一個 isNotEmpty() 介面(非空) return func ? jQuery.inArray(func, list) > -1 : !!(list && list.length); }, empty: function() { list = []; return this; }, disable: function() { // 徹底禁用該對象, stack禁用, memory禁用 list = stack = memory = undefined; return this; }, disabled: function() { return !list; }, lock: function() { stack = undefined; // 如果memory沒有儲存調用狀態,直接禁用這個對象(可能是從未調用就被鎖定,或者沒有memory欄位) if (!memory) { self.disable(); } return this; }, locked: function() { return !stack; }, fireWith: function (context, args) { args = args || []; var data = [context, args]; if (list && (fired === false || stack) ) { if (firing) { // 進入條件: firing === true && stack 說明當前正在執行回呼函數隊列 stack.push(data); // stack其實是一個隊列結構,這裡用 stack 有些混淆 } else { // 進入條件一: firing === false && fired === false 說明從來沒有 fire()過 // 進入條件二: firing === false && fired === true && stack = [] 說明至少調用過一次,而且當前允許多次調用,可以通過lock()鎖定 fire(args); } } return this; }, fire: function() { self.fireWith(this, arguments); return this; }, fired: function() { return !!fired; } }; return self;};
4、胡思亂想
jQuery.Callbacks() 方法的核心是 fire() 方法,將該 fire() 方法被封裝在函數中不可直接存取,因此像 memory、firing、fired 這些狀態對於外部內容來說是不可更改的。
還有需要注意的是,如果回呼函數中使用了 this 對象,可以直接用這個 this 來訪問self對象的公有API。當然,也可以用 fireWith() 自己指定 this 的引用對象。
jQuery.Callbacks()的核心思想是 Pub/Sub 模式,建立了程式間的鬆散耦合和高效通訊。
更多關於jQuery相關內容感興趣的讀者可查看本站專題:《jQuery常用外掛程式及用法總結》、《jquery中Ajax用法總結》、《jQuery表格(table)操作技巧匯總》、《jQuery拖拽特效與技巧總結》、《jQuery擴充技巧總結》、《jQuery常見經典特效匯總》、《jQuery動畫與特效用法總結》及《jquery選取器用法總結》
希望本文所述對大家jQuery程式設計有所協助。