<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 2297字,需瀏覽 5分鐘

           ·

          2021-07-27 20:14

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

          發(fā)布-訂閱模式里面包含了三個(gè)模塊,發(fā)布者,訂閱者和處理中心。這里處理中心相當(dāng)于報(bào)刊辦事大廳。
          發(fā)布者相當(dāng)與某個(gè)雜志負(fù)責(zé)人,他來(lái)中心這注冊(cè)一個(gè)的雜志,而訂閱者相當(dāng)于用戶,我在中心訂閱了這分雜志。
          每當(dāng)發(fā)布者發(fā)布了一期雜志,辦事大廳就會(huì)通知訂閱者來(lái)拿新雜志。這樣在結(jié)合下面的圖應(yīng)該很好理解了。


          其實(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)


          瀏覽 65
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人黄片视频在线 | 一级国产黄色片 | 亚洲天堂小说 | 日韩三级中文字幕电影在线 | 欧美性猛交ⅩXXX无码视频 |