本文實例講述了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程序設計有所幫助。
新聞熱點
疑難解答