摘要:接受個參數,包括事件的名稱,回調函數和回調函數執行的上下文環境。保留回調函數在數組中取出對應的以及中的函數。當然,你同樣可以在綁定的回調函數執行前手動通過將其移除。
Backbone源碼解讀
Backbone在流行的前端框架中是最輕量級的一個,全部代碼實現一共只有1831行1。從前端的入門再到Titanium,我雖然幾次和Backbone打交道但是卻對它的結構知之甚少,也促成了我想讀它的代碼的原始動力。這個系列的文章主要目的是分享Backbone框架中可以用于日常開發的實踐參考,力求能夠簡明扼要的展現Backbone Modal, Controller和Sync這些核心內容,希望能夠對大家學習和使用Backbone有一些幫助。
這個系列的文章將包括以下3篇內容:
Backbone源碼解讀之Events實現
Backbone源碼解讀之Router, History實現
Backbone源碼解讀之Model, Collection, Sync實現
本文是它的第一篇《Backbone源碼解讀之Events實現》
Backbone Events實現Backbone的Event是整個框架運轉的齒輪。它的優美之處在于它是Backbone的一個基礎方法,通過_.extend的方法Mixin到Backbone的每一個模塊中。
//Model _.extend(Model.prototype, Events, { changed: null, //other Model prototype methods //... }Event的基礎概念
事件的管理是一個綁定在Events這個命名空間中的_events對象來實現的。
它的結構是name: [callback functions]的key-callback_array鍵值對。
this._events = { change: [callback_on_change1, callback_on_change2, ....], .... }
當事件發生的時候,event從這個對象中根據事件的名稱取得回調函數數組,然后循環執行每個回調函數,也就說明了為什么多次綁定會重復觸發多次事件。
Event包括on, off, trigger三個基礎方法,其余的所有方法均是對它們的擴展。
on(name, callback, context)on接受3個參數,包括事件的名稱,回調函數和回調函數執行的上下文環境。其中context是可選參數,如果你不是很熟悉JS的執行上下文環境可以暫時不用管它。
拋開所有Backbone的花哨的檢查,執行on的操作本質就是向_events中name對應的回調函數數組[callback functions]中Push新的函數。
簡單來說代碼實現就是這個樣子:
Events.on = function(name, callback, context) { if (callback) { var handlers = events[name] || (events[name] = []); handlers.push({callback: callback, context: context, ctx: context || this}); } return this; };
至于你在看源代碼的時候會長很多,那是因為一方面Backbone要處理關于_events以及_events[name]未初始化的兩種特殊情況。另一方面eventsApi,onApi這些方法是為了處理on時候你傳入的不是一個string類型的名稱和一個callback函數所做的條件處理。
例如下面兩種方法都是合法的:
//傳入一個名稱,回調函數的對象 model.on({ "change": on_change_callback, "remove": on_remove_callback }); //使用空格分割的多個事件名稱綁定到同一個回調函數上 model.on("change remove", common_callback);
但是核心其實都是同一個綁定函數。
值得注意的一點是由于Backbone接受all作為name的參數,并且將回調函數保存在_events.all中,關于它的執行詳細可以參考trigger。
off(name, callback, context)與on不同,off的3個參數都是可選的。
如果沒有任何參數的時候,off相當于把對應的_events對象整體清空。
if (!name && !callback && !context) { this._events = void 0; return this; }
如果有name參數但是沒有具體清除哪個callback的時候,則把_events[name]對應的內容全部清空。
if (!callback && !context) { delete this._events[name]; continue; }
如果還有進一步詳細的callback和context的情況下,則進入[callback functions]中進行檢查,移除具體一個回調函數的條件非常嚴苛,必須要求上下文和函數與原來完全一致,也就是說如果傳入的callback或者context不是原有on對象的引用,而是復制的話,這里的off是無效的。
var remaining = []; if( callback && callback !== handler.callback && callback !== handler.callback._callback || context && context !== handler.context ){ //保留回調函數在數組中 }trigger(name)
trigger取出name對應的_events[name]以及_event.all中的callback函數。
需要注意的一點是,觸發對應名稱的callback和all的callback使用了不一樣的參數,all的參數中還包含了當前事件的名稱。
//當綁定3個以下回調函數的時候Backbone會做如下優化處理,據說這樣是可以提高執行效率的。 var triggerEvents = function(events, args) { var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; switch (args.length) { case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; } };最簡單的Backbone事件使用
從使用上來講,對一個對象進行事件的on綁定。然后在同一個對象的其他函數執行過程中,或者其他的對象中,觸發該對象的trigger方法和對應的事件名稱來執行其上綁定的callback函數。
其他輔助函數接下來再看看Event中進一步定義了哪些其他輔助函數
once(name, callback, context)效果相同與on,不過對應的callback函數僅執行一次。當然,你同樣可以在once綁定的回調函數執行前手動通過off將其移除。
來看看Once的實現,由于添加了執行過程中的移除方法,once在實際實行on的時候使用了如下匿名函數:
var once = _.once(function() {function(){ self.off(name, once); callback.apply(this, arguments); }); return this.on(name, once, context);
但是細心的你一定發現,保存在_event數組中的函數是once這個匿名函數了。但是用戶并不知道Backbone的這些操作,在取消綁定時仍然會使用原來的回調函數來試圖解除綁定。上面我們也提到,必須使用完全一致的函數才能夠取消綁定,那么為什么還能夠成功呢?
這里Backbone做了一個小小的操作,不知道你有沒有注意到上面off函數中有這樣一行內容?
callback !== handler.callback._callback
既然callback是我們傳入的回調函數,那么哪里來的_callback這個屬性呢?答案就在once里面。
var once = _.once(function() {...取消綁定,執行callback); once._callback = callback;
也就是Backbone在返回之前悄悄的為once這個函數添加了一個_callback的屬性,用來保存原來的回調函數,這樣用戶在傳入原來的回調函數取消綁定的時候,off會檢查函數時候有_callback這個屬性和用戶傳入的函數匹配,同樣可以取消綁定。
listenTo(obj, name, callback)、listenToOnce(obj, name, callback)和stopListening(obj, name, callback)除了將對象本身expose給另一個對象,讓另一個對象執行trigger方法觸發該對象上綁定的event以外。Event還進一步提供了listenTo系列的方法,執行邏輯正好與on相反。
例如有如下要求,當B對象上發生事件b的時候,觸發A對象的callbackOnBEvent函數。
// 使用on的情況下 B.on(“b”, A.callbackOnBEvent) // 使用listenTo的情況下 A.listenTo(B, “b”, callbackOnEvent);
從實現上看,它門的區別就在于誰負責管理這個事件。第一個模型中,B就像是整個系統的master,負責事件到達的時候的分發,讓不同的對象(如A)執行對應的方法。第二個模型中,B更像是一個信息棧,A監聽B上發生的事件,并且在對應事件到達的時候觸發自身相應的回調函數。兩者并無好壞之分,但是從系統架構上來說因為本身回調函數的上下文環境就是A,所以listenTo的方式可能會來的更加自然,而且由A自己來控制什么時候移除回調的執行,也可以讓代碼的解耦程度更高。
超越Backbone使用Event方法來處理異步請求讓代碼的可讀性大大增加。如果你的單頁面應用恰好使用了Backbone作為前端框架,將Event通過Backbone.Events這個變量暴露出來,你可以使用類似Model擴展的方法
//Your object _.extend(your_object.prototype, Backbone.Events, { //other prototype methods //... }
這樣你的Object也就具有了彼此綁定事件、觸發事件的能力。
即便你的前端并沒有使用Backbone,由于Events并不依賴Backbone的其他部分實現,你完全可以將它放到自己的代碼lib中,作為一個基礎方法來使用。
類似的方式你也可以經常在Node的后端看到
var util = require("util"); var events = require("events"); function MyStream() { events.EventEmitter.call(this); } util.inherits(MyStream, events.EventEmitter);
總之,我個人是非常推薦多多使用Event來替代層級的Callback結構。
根據2015年4月 穩定版本Backbone.js 1.1.2的注釋版本。Master上的代碼和注釋版本稍有出入,哪位大神知道為什么嗎????
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85600.html
1. 開場 1.1 MVC? MVC是一種GUI軟件的一種架構模式。它的目的是將軟件的數據層(Model)和視圖(view)分開。Model連接數據庫,實現數據的交互。用戶不能直接和數據打交道,而是需要通過操作視圖,然后通過controller對事件作出響應,最后才得以改變數據。最后數據改變,通過觀察者模式更新view。(所以在這里需要用到設計模式中的觀察者模式) 1.2 Smalltalk-80...
摘要:以為例構造函數的內容構造函數的內部一般會做以下幾個操作各種給內部對象設置屬性。為什么呢源碼做出了解釋。在里面會調用用戶傳入的回調函數并觸發事件表示已經同步了。整個的源碼事實上就是這兩組東西。 1. 開場 強烈建議一邊看著源碼一邊讀本文章,本文不貼大段代碼。源碼地址。在寫backbone應用的時候,說實話,大部分的時間都是在寫這三個模塊的內容。關于這三個模塊的分析網上隨隨便便就能找到一堆...
摘要:個人認為,讀懂老牌框架的源代碼比會用流行框架的要有用的多。另外,源代碼中所有的以開頭的方法,可以認為是私有方法,是沒有必要直接使用的,也不建議用戶覆蓋。 寫在前面 backbone是我兩年多前入門前端的時候接觸到的第一個框架,當初被backbone的強大功能所吸引(當然的確比裸寫js要好得多),雖然現在backbone并不算最主流的前端框架了,但是,它里面大量設計模式的靈活運用,以及令...
摘要:個人認為,讀懂老牌框架的源代碼比會用流行框架的要有用的多。另外,源代碼中所有的以開頭的方法,可以認為是私有方法,是沒有必要直接使用的,也不建議用戶覆蓋。 寫在前面 backbone是我兩年多前入門前端的時候接觸到的第一個框架,當初被backbone的強大功能所吸引(當然的確比裸寫js要好得多),雖然現在backbone并不算最主流的前端框架了,但是,它里面大量設計模式的靈活運用,以及令...
摘要:最近對主要對源碼進行了閱讀,分別解讀了,,目錄如下希望大家能互相交流 最近對backbone主要對源碼進行了閱讀,分別解讀了Backbone.Model,Backbone.View , Backbone.Collection,Backbone.Event,目錄如下: Backbone.View Backbone.Collection Backbone.Model Backbone....
閱讀 1341·2023-04-25 23:42
閱讀 2808·2021-11-19 09:40
閱讀 3520·2021-10-19 11:44
閱讀 3529·2021-10-14 09:42
閱讀 1860·2021-10-13 09:39
閱讀 3821·2021-09-22 15:43
閱讀 665·2019-08-30 15:54
閱讀 1448·2019-08-26 13:32