<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [toc] ## Callbacks 的使用 jQuery 內部提供了很多基礎功能的方法,比如 $.ajax()、$.each() 和 $.Callbacks(),這些方法既可以在內部進行使用,又可以被開發者拿到外部單獨使用。 Callbacks 的支持的方法有幾個主要的,add、fire、remove 和 disable,比如官方有一個例子: ``` // 這兩個作為 callback 函數 function fn1( value ) { console.log( value ); } function fn2( value ) { fn1("fn2 says: " + value); return false; } // 調用 jQuery 的 Callbacks 生成 callbacks var callbacks = $.Callbacks(); callbacks.add( fn1 ); callbacks.fire( "foo!" ); // 'foo!' callbacks.add( fn2 ); callbacks.fire( "bar!" ); // 'bar!' // 'fn2 says: bar!' ``` 從基本 demo 可以看出,$.Callbacks() 函數生成了一個 callbacks 對象,這個對象的 .add() 方法是添加回調函數,而 .fire() 方法則是執行回調函數。 .remove() 方法是移除回調函數: ``` var callbacks = $.Callbacks(); callbacks.add( fn1 ); callbacks.fire( "foo!" ); // 'foo!' callbacks.add( fn2 ); callbacks.fire( "bar!" ); // 'bar!' // 'fn2 says: bar!' callbacks.remove( fn2 ); callbacks.fire( "foobar" ); // 'foobar' ``` $.Callbacks() 還支持幾個參數,表示執行回調的幾種效果,$.Callbacks('once'): - once: 確保這個回調列表只執行 .fire() 一次(像一個遞延 Deferred) - memory: 保持以前的值,將添加到這個列表的后面的最新的值立即執行調用任何回調 (像一個遞延 Deferred) - unique: 確保一次只能添加一個回調(所以在列表中沒有重復的回調) - stopOnFalse: 當一個回調返回false 時中斷調用 此方法還支持多個參數,比如$.Callbacks('once memory'),具體的使用請參考這個鏈接。 ## Callbacks 的源碼 在放 jQuery 3.0 的源碼之前,我們先來簡單的模擬一下 Callbacks 函數,來實現其基本的功能: ``` var Callbacks = function(){ var Cb = { callbacks: [], add: function(fn){ this.callbacks.push(fn); return this; }, fire: function(value){ this.callbacks.forEach(function(fn){ fn(value); }); return this; } } return Cb; } // 測試 var callbacks = Callbacks(); callbacks.add(fn1); callbacks.fire('test'); //'test' ``` 可以看到其實一個簡單的 Callbacks 函數實現起來還是非常簡單的。 整個的 Callbacks 源碼其實大致如下: ``` jQuery.Callbacks = function(options){ // 先對參數進行處理,比如 once、unique 等 options = createOptions(options); // 參數定義,包括一些 flag 和 callbacks 數組 var list = [], queue = [] ... // fire 是遍歷數組,回掉函數的執行 var fire = function(){ ... } // self 是最終返回的對象 var self = { add: function(){...}, remove: function(){...}, has: function(){...}, disable: function(){...}, fireWith: function(){...},//這個其實是 fire 函數的執行 fire: function(){...} ... } return self; } ``` 因為前面已經簡單的介紹過了如何實現一個基本的 Callbacks 函數,這里稍微清晰了一點,來看下 createOptions 函數,這個函數主要是對類似于 $.Callbacks('once memory')類型對 callback 進行 flag 分離: ``` function createOptions(options) { var object = {}; jQuery.each(options.match(rnothtmlwhite) || [], function (_, flag) { object[flag] = true; }); return object; } ``` 其中 rnothtmlwhite 是一個正則表達式` /[^\x20\t\r\n\f]+/g`,用來獲得所有的 flag 標志。createOptions 的結果是一個對象,鍵值分別是 flag 和 boolean。 那么現在的主要的問題,就全在那些 flag 上面來,"once memory unique stopOnFalse"。 源碼奉上: ``` jQuery.Callbacks = function(options) { // flag 處理 options = typeof options === "string" ? createOptions(options) : jQuery.extend({}, options); var // Flag to know if list is currently firing firing, // Last fire value for non-forgettable lists memory, // Flag to know if list was already fired fired, // Flag to prevent firing locked, // Actual callback list list = [], // Queue of execution data for repeatable lists queue = [], // Index of currently firing callback (modified by add/remove as needed) firingIndex = -1, // Fire callbacks fire = function() { // 只執行一次,以后都不執行了 locked = locked || options.once; // Execute callbacks for all pending executions, // respecting firingIndex overrides and runtime changes fired = firing = true; for (; queue.length; firingIndex = -1) { memory = queue.shift(); while (++firingIndex < list.length) { // 回調執行函數,并檢查是否 stopOnFalse,并阻止繼續運行 if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) { // Jump to end and forget the data so .add doesn't re-fire firingIndex = list.length; memory = false; } } } // Forget the data if we're done with it if (!options.memory) { memory = false; } firing = false; // locked 在這里實現 if (locked) { // 雖然鎖住但是是 memory,保留 list 以后使用 if (memory) { list = []; // 拜拜... } else { list = ""; } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if (list) { // If we have memory from a past run, we should fire after adding if (memory && !firing) { firingIndex = list.length - 1; queue.push(memory); } (function add(args) { jQuery.each(args, function(_, arg) { if (jQuery.isFunction(arg)) { if (!options.unique || !self.has(arg)) { list.push(arg); } } else if (arg && arg.length && jQuery.type(arg) !== "string") { // Inspect recursively add(arg); } }); })(arguments); if (memory && !firing) { fire(); } } return this; }, // Remove a callback from the list remove: function() { jQuery.each(arguments, function(_, arg) { var index; while ((index = jQuery.inArray(arg, list, index)) > -1) { list.splice(index, 1); // Handle firing indexes if (index <= firingIndex) { firingIndex--; } } }); return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function(fn) { return fn ? jQuery.inArray(fn, list) > -1 : list.length > 0; }, // Remove all callbacks from the list empty: function() { if (list) { list = []; } return this; }, // Disable .fire and .add // Abort any current/pending executions // Clear all callbacks and values disable: function() { locked = queue = []; list = memory = ""; return this; }, disabled: function() { return !list; }, // Disable .fire // Also disable .add unless we have memory (since it would have no effect) // Abort any pending executions lock: function() { locked = queue = []; if (!memory && !firing) { list = memory = ""; } return this; }, locked: function() { return !!locked; }, // Call all callbacks with the given context and arguments fireWith: function(context, args) { if (!locked) { args = args || []; args = [context, args.slice ? args.slice() : args]; queue.push(args); if (!firing) { fire(); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith(this, arguments); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; ``` 總的來說,這種 pub/sub 模式的代碼還是比較容易看懂的,有些疑問的地方,比如源碼中其實有兩個數組,list 是隊列數組,本應該叫做 queue,但是 queue 數組已經被定義,且 queue 的作用是用來存儲 fire 執行時的參數,這點不能搞混。 還有就是當整個代碼 firing 這個參數,導致當函數正在運行的時候,即執行兩次 fire 的時候,需要補充 queue 元素,但 fire() 函數只執行一次。 ## 總結 jQuery.Callbacks 沿用 jQuery 一貫的套路,最后 return self,剛看第一遍第二遍的時候,有點模模糊糊的,主要還是 once、memory 等 flag 參數干擾我的視線,尤其是其這些 flag 標志的實現,難受。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看