jQuery.Callbacks()回呼函數隊列用法詳解_jquery

來源:互聯網
上載者:User

本文執行個體講述了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程式設計有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.