我們經常會這樣使用函數回調:
? 事件觸發通知
? 資源加載通知
? 定時器延時
? ajax、動畫通知等等。
以上都是很單一的事件監聽回調的處理方式,但是jQuery把回調函數的用法設計成一個更高的抽像,用于解耦與分離變化。
如何理解這個設計?我們看下面的例子。
例子一:
jQuery針對Dom的處理提供了append、prepend、before、after等方法的處理,這幾個方法的特征:
1、參數的傳遞可以是HTML字符串、DOM元素、元素數組或者jQuery對象
2、為了優化性能針對節點的處理需要生成文檔碎片
可見幾個方法都是需要實現這2個特性的,那么我們應該如何處理?
高層接口:
before: function() { return this.domManip(arguments, function(elem) { if (this.parentNode) { this.parentNode.insertBefore(elem, this); } }); }, after: function() { return this.domManip(arguments, function(elem) { if (this.parentNode) { this.parentNode.insertBefore(elem, this.nextSibling); } }); },
底層實現:
domManip: function(args, callback) { // Flatten any nested arrays args = concat.apply([], args); // We can't cloneNode fragments that contain checked, in WebKit if (isFunction || //多參數處理 self.domManip(args, callback); } if (l) { //生成文檔碎片 fragment = jQuery.buildFragment(args, this[0].ownerDocument, false, this); callback.call(this[i], node, i); } return this; }
我們觀察下jQuery的實現,通過抽象出一個domManip方法,然后在這個方法中處理共性,合并多個參數的處理與生成文檔碎片的處理,然后最終把結果通過回調函數返回給每一個調用者。
例子二:
在很多時候需要控制一系列的函數順序執行。那么一般就需要一個隊列函數來處理這個問題。
我們看一段代碼:
function Aaron(List, callback) { setTimeout(function() { var task; if (task = List.shift()) { task(); //執行函數 } if (List.length > 0) { //遞歸分解 arguments.callee(List) } else { callback() } }, 25) } //調用 ?Aaron([ function() { alert('a') }, function() { alert('b') }, function() { alert('c') } ], function() { alert('callback') }) // 分別彈出 ‘a’ , ‘b’ ,'c',’callback
傳入一組函數參數,靠遞歸解析,分個執行,其實就是靠setTimeout可以把函數加入到隊列末尾才執行的原理,這樣的寫法就有點就事論事了,聚合對象完全是一個整體,無法再次細分出來,所以我們需要一種方案,用來管理分離每一個獨立的對象。
我們換成jQuery提供的方式:
var callbacks = $.Callbacks(); callbacks.add(function() { alert('a'); }) callbacks.add(function() { alert('b'); }) callbacks.fire(); //輸出結果: 'a' 'b'
是不是便捷很多了,代碼又很清晰,所以Callbacks它是一個多用途的回調函數列表對象,提供了一種強大的方法來管理回調函數隊列。
那么我們使用回調函數,總的來說弱化耦合,讓調用者與被調用者分開,調用者不關心誰是被調用者,所有它需知道的,只是存在一個具有某種特定原型、某些限制條件的被調用函數。
請驗證,完成請求
由于請求次數過多,請先驗證,完成再次請求
打開微信掃碼自動綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報