JavaScript的發(fā)布訂閱模式

這里要說(shuō)明一下什么是發(fā)布-訂閱模式。

其實(shí)就是將發(fā)布者和訂閱者解耦了,在實(shí)際開發(fā)中,經(jīng)常會(huì)遇到某個(gè)方法內(nèi)處理很多的邏輯,最簡(jiǎn)單的就是直接在方法內(nèi)直接寫。這種是高度耦合的面向過(guò)程的寫法。對(duì)于代碼維護(hù)不友好。
而發(fā)布-訂閱模式就是將兩者分離。我觸發(fā)了某個(gè)事件(這里我們將觸發(fā)該方法定義為事件),我只向調(diào)度中心通知,我并不知道調(diào)度中心內(nèi)會(huì)怎么處理,有多少個(gè)人響應(yīng)。我只管通知。
而訂閱者只管在調(diào)度中心訂閱,有人調(diào)用它才響應(yīng)。
還有一點(diǎn)就是假設(shè)我們有3個(gè)js文件,事件觸發(fā)在a.js內(nèi),而響應(yīng)該事件的在b.js和c.js內(nèi),要是用常規(guī)調(diào)用的方法的話,就要把b.js和c.js的方法傳到a.js內(nèi)。這是一個(gè)非常麻煩的操作。
而發(fā)布-訂閱模式是將調(diào)度中心掛在了全局,我們只管調(diào)用調(diào)度中心相應(yīng)的方法注冊(cè)和訂閱。
ps:還有一點(diǎn)要注意的,很多人會(huì)把觀察者模式和發(fā)布-訂閱模式混淆,其實(shí)兩者之間還是有點(diǎn)區(qū)別的,不過(guò)在本文我不會(huì)詳細(xì)講。
下面我們來(lái)實(shí)現(xiàn)一個(gè)發(fā)布-訂閱模式的類
class Event {constructor () {}// 首先定義一個(gè)事件容器,用來(lái)裝事件數(shù)組(因?yàn)橛嗛喺呖梢允嵌鄠€(gè))handlers = {}// 事件添加方法,參數(shù)有事件名和事件方法addEventListener (type, handler) {// 首先判斷handlers內(nèi)有沒有type事件容器,沒有則創(chuàng)建一個(gè)新數(shù)組容器if (!(type in this.handlers)) {this.handlers[type] = []}// 將事件存入this.handlers[type].push(handler)}// 觸發(fā)事件兩個(gè)參數(shù)(事件名,參數(shù))dispatchEvent (type, ...params) {// 若沒有注冊(cè)該事件則拋出錯(cuò)誤if (!(type in this.handlers)) {return new Error('未注冊(cè)該事件')}// 便利觸發(fā)this.handlers[type].forEach(handler => {handler(...params)})}// 事件移除參數(shù)(事件名,刪除的事件,若無(wú)第二個(gè)參數(shù)則刪除該事件的訂閱和發(fā)布)removeEventListener (type, handler) {// 無(wú)效事件拋出if (!(type in this.handlers)) {return new Error('無(wú)效事件')}if (!handler) {// 直接移除事件delete this.handlers[type]} else {const idx = this.handlers[type].findIndex(ele => ele === handler)// 拋出異常事件if (idx === undefined) {return new Error('無(wú)該綁定事件')}// 移除事件this.handlers[type].splice(idx, 1)if (this.handlers[type].length === 0) {delete this.handlers[type]}}}}
ok,到現(xiàn)在為止就已經(jīng)實(shí)現(xiàn)了基本發(fā)布訂閱的功能了,其實(shí)很簡(jiǎn)單,如果還有什么奇怪的需求,都可以通通往里面加。
下面是完整的使用demo
var event = new Event() // 創(chuàng)建event實(shí)例// 定義一個(gè)自定義事件:"load"function load (params) {console.log('load', params)}event.addEventListener('load', load)// 再定義一個(gè)load事件function load2 (params) {console.log('load2', params)}event.addEventListener('load', load2)// 觸發(fā)該事件event.dispatchEvent('load', 'load事件觸發(fā)')// 移除load2事件event.removeEventListener('load', load2)// 移除所有l(wèi)oad事件event.removeEventListener('load')
學(xué)習(xí)更多技能
請(qǐng)點(diǎn)擊下方公眾號(hào)
![]()

評(píng)論
圖片
表情
