在最近的構建的一個網絡推送 服務的項目中, 我想讓我的UI響應應用程序級別的事件(語義上,如果你會的話) 因為有幾個組件需要從系統中獲取信息,但不相互依賴,我希望他們能夠獨立管理自己的“業務邏輯”.
我環顧四周,很多不同的工具來幫助我, 但是因為我經常有很嚴重的NIH綜合症和我認為人們可以很快實現自己的基礎元素, 我決定迅速把它綁定到一個簡單的客戶端PubSub服務— 它工作得很好,滿足了我的需求.
我在考慮是否應該使用一個自定義的DOM事件和利用現有的DOM已經提供給開發者的基礎設施,透過使用 addEventListener函數,能夠具有發布事件和消費事件的能力 — 唯一的問題是,你必須把事件綁定到一個DOM元素或window,因為你沒有一個繼承或混合了EventTarget的模型。
思考: 有目標為對象,將有助於避免創建自定義的發布訂閱系統的需要.
有了這個約束, 一段代碼已經出現,不管是否錯誤至少是我自己寫的,我草擬了一個粗略的計劃:
/* When a user is added, do something useful (like update UI) */EventManager.subscribe('useradded', function(user) { console.log(user) });/* The UI submits the data, lets publish the event. */form.onsubmit(function(e) { e.preventDefault(); // do something with user fields EventManager.publish('useradded', user); })
所有這一切並不新鮮. Redux 和許多其他的系統大多數情況下已經是這樣做的了, 它們負責幫你管理應用狀態.在我的腦海中,我確定不需要一個狀態模型來管理狀態而且和瀏覽器中的狀態區分開來。
這是一個非常簡單的實現,但是抽象非常重要。至少對我來說是這樣的。
var EventManager = new (function() { var events = {}; this.publish = function(name, data) { return new Promise(function(resolve, reject) { var handlers = events[name]; if(!!handlers === false) return; handlers.forEach(function(handler) { handler.call(this, data); }); resolve(); }); }; this.subscribe = function(name, handler) { var handlers = events[name]; if(!!handlers === false) { handlers = events[name] = []; } handlers.push(handler); }; this.unsubscribe = function(name, handler) { var handlers = events[name]; if(!!handlers === false) return; var handlerIdx = handlers.indexOf(handler); handlers.splice(handlerIdx); }; });
我的簡單的發布訂閱(PubSub)系統可能充滿了bug, 但是我喜歡它。