国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

js設(shè)計(jì)模式——發(fā)布訂閱模式

這篇具有很好參考價(jià)值的文章主要介紹了js設(shè)計(jì)模式——發(fā)布訂閱模式。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、概述

發(fā)布訂閱模式是一種常用的設(shè)計(jì)模式,它定義了一種一對多的關(guān)系,讓多個(gè)訂閱者對象同時(shí)監(jiān)聽某一個(gè)主題對象,當(dāng)主題對象發(fā)生變化時(shí),它會通知所有訂閱者對象,使它們能夠自動(dòng)更新 。

二、優(yōu)缺點(diǎn)

1. 優(yōu)點(diǎn):
  • 實(shí)現(xiàn)了發(fā)布者和訂閱者之間的解耦,提高了代碼的可維護(hù)性和復(fù)用性。
  • 支持異步處理,可以實(shí)現(xiàn)事件的延遲觸發(fā)和批量處理。
  • 支持多對多的通信,可以實(shí)現(xiàn)廣播和組播的功能。
2. 缺點(diǎn):
  • 可能會造成內(nèi)存泄漏,如果訂閱者對象沒有及時(shí)取消訂閱,就會一直存在于內(nèi)存中。
  • 可能會導(dǎo)致程序的復(fù)雜性增加,如果訂閱者對象過多或者依賴關(guān)系不清晰,就會增加程序的調(diào)試難度。
  • 可能會導(dǎo)致信息的不一致性,如果發(fā)布者在通知訂閱者之前或之后發(fā)生了變化,就會造成數(shù)據(jù)的不同步。

三、適用場景

發(fā)布訂閱模式適用于以下場景:

  • 當(dāng)一個(gè)對象的狀態(tài)變化需要通知其他多個(gè)對象時(shí),可以使用發(fā)布訂閱模式來實(shí)現(xiàn)松耦合的通信
  • 當(dāng)一個(gè)事件或消息需要廣泛傳播或分發(fā)給多個(gè)接收者時(shí),可以使用發(fā)布訂閱模式來實(shí)現(xiàn)高效的消息分發(fā)
  • 當(dāng)一個(gè)系統(tǒng)需要支持異步處理或批量處理時(shí),可以使用發(fā)布訂閱模式來實(shí)現(xiàn)事件的延遲觸發(fā)或批量觸發(fā)

四、代碼示例

在JavaScript中,實(shí)現(xiàn)發(fā)布訂閱模式的基本思想是:

  • 定義一個(gè)發(fā)布者對象,它有一個(gè)緩存列表,用于存放訂閱者對象的回調(diào)函數(shù)
  • 定義一個(gè)訂閱方法,用于向緩存列表中添加回調(diào)函數(shù)
  • 定義一個(gè)取消訂閱方法,用于從緩存列表中移除回調(diào)函數(shù)
  • 定義一個(gè)發(fā)布方法,用于遍歷緩存列表,依次執(zhí)行回調(diào)函數(shù),并傳遞相關(guān)參數(shù)

下面是一個(gè)簡單的發(fā)布訂閱模式的代碼示例 :

// 定義一個(gè)發(fā)布者對象
var pub = {
  // 緩存列表,存放訂閱者回調(diào)函數(shù)
  list: {},
  // 訂閱方法
  subscribe: function(key, fn) {
    // 如果沒有該消息的緩存列表,就創(chuàng)建一個(gè)空數(shù)組
    if (!this.list[key]) {
      this.list[key] = [];
    }
    // 將回調(diào)函數(shù)推入該消息的緩存列表
    this.list[key].push(fn);
  },
  // 取消訂閱方法
  unsubscribe: function(key, fn) {
    // 如果有該消息的緩存列表
    if (this.list[key]) {
      // 遍歷緩存列表
      for (var i = this.list[key].length - 1; i >= 0; i--) {
        // 如果存在該回調(diào)函數(shù),就從緩存列表中刪除
        if (this.list[key][i] === fn) {
          this.list[key].splice(i, 1);
        }
      }
    }
  },
  // 發(fā)布方法
  publish: function() {
    // 獲取消息類型
    var key = Array.prototype.shift.call(arguments);
	// 獲取該消息的緩存列表
	var fns = this.list[key];
	// 如果沒有訂閱該消息,就返回
	if (!fns || fns.length === 0) {
  	return;
	}
	// 遍歷緩存列表,執(zhí)行回調(diào)函數(shù)
	for (var i = 0; i < fns.length; i++) {
  		fns[i].apply(this, arguments);
	}
  }
};

// 定義一個(gè)訂閱者對象A 
var subA = function(name) { console.log('A收到了消息:' + name); };
// 定義一個(gè)訂閱者對象B 
var subB = function(name) { console.log('B收到了消息:' + name); };

// A訂閱了test消息 
pub.subscribe('test', subA);
// B訂閱了test消息 
pub.subscribe('test', subB);

// 發(fā)布了test消息,傳遞了參數(shù) 'hello'
pub.publish('test', 'hello');
// 輸出: 
// A收到了消息:hello 
// B收到了消息:hello

// A取消訂閱了test消息 
pub.unsubscribe('test', subA);

// 發(fā)布了test消息,傳遞了參數(shù) 'world'
pub.publish('test', 'world');
// 輸出: // B收到了消息:world

五、 Vue2 響應(yīng)式系統(tǒng)實(shí)現(xiàn)原理

Vue 中,每個(gè)組件實(shí)例都有相應(yīng)的 watcher 實(shí)例對象,它會在組件渲染的過程中把屬性記錄為依賴,之后當(dāng)依賴項(xiàng)的 setter 被調(diào)用時(shí),會通知 watcher 重新計(jì)算,從而致使它關(guān)聯(lián)的組件得以更新。

1. 監(jiān)聽器

實(shí)現(xiàn)一個(gè)方法,這個(gè)方法會對需要監(jiān)聽的數(shù)據(jù)對象進(jìn)行遍歷、給它的屬性加上定制的 gettersetter 函數(shù)。這樣但凡這個(gè)對象的某個(gè)屬性發(fā)生了改變,就會觸發(fā) setter 函數(shù),進(jìn)而通知到訂閱者。

// observe 方法遍歷并包裝對象屬性
function observe(target) {
  // 若target是一個(gè)對象,則遍歷它
  if(target && typeof target === 'object') {
    Object.keys(target).forEach((key)=> {
      // defineReactive方法會給目標(biāo)屬性裝上“監(jiān)聽器”
      defineReactive(target, key, target[key])
    })
  }
}

// 定義 defineReactive 方法
function defineReactive (obj, key, val) {
  /* 一個(gè) Dep 類對象 */
  const dep = new Dep();
  /* 屬性值也可能是 object 類型,這種情況下需要調(diào)用 observe 進(jìn)行遞歸遍歷 */
  observe(val);

  // 為當(dāng)前屬性安裝監(jiān)聽器
  Object.defineProperty(obj, key, {
    // 可枚舉
    enumerable: true,
    // 不可配置
    configurable: true,
    get: function reactiveGetter () {
      /* 將 Dep.target(即當(dāng)前的 Watcher 對象存入 dep 的 subs 中) */
      dep.addSub(Dep.target);
      return val;         
    },
    // 監(jiān)聽器函數(shù)
    set: function reactiveSetter (newVal) {
      if (newVal === val) return;
      /* 在 set 的時(shí)候觸發(fā) dep 的 notify 來通知所有的 Watcher 對象更新視圖 */
      dep.notify();
    }
  });
}

2. 訂閱者
// 定義訂閱者類 Dep
class Dep {
  constructor () {
    /* 初始化訂閱隊(duì)列 */
    this.subs = [];
  }

  /* 增加訂閱者,在 subs 中添加一個(gè) Watcher 對象 */
  addSub (sub) {
    this.subs.push(sub);
  }

  /* 通知所有 Watcher 對象更新視圖 */
  notify () {
    this.subs.forEach((sub) => {
      sub.update();
    })
  }
}

3. 觀察者
class Watcher {
  constructor () {
    /* 在 new 一個(gè) Watcher 對象時(shí)將該對象賦值給 Dep.target,在 get 中會用到 */
    Dep.target = this;
  }

  /* 更新視圖的方法 */
  update () {
    console.log("視圖更新啦~");
  }
}

Dep.target = null;
4. Vue 組裝
class Vue {
  constructor(options) {
    this._data = options.data;
    observe(this._data);
    /* 新建一個(gè) Watcher 觀察者對象,這時(shí)候 Dep.target 會指向這個(gè) Watcher 對象 */
    new Watcher();
    /* 在這里模擬 render 的過程,為了觸發(fā) test 屬性的 get 函數(shù) */
    console.log('render~', this._data.test);
  }
}
let vm = new Vue({
  data:{
    test:"origin"
  }
});

vm._data.test="測試更改!";

/* 運(yùn)行結(jié)果
 * render~ origin
 * 視圖更新啦~
 * "測試更改!"
*/

六、實(shí)現(xiàn)一個(gè) Event Bus / Event Emitter

Event Bus / Event Emitter 作為全局事件總線,它起到的是一個(gè)溝通橋梁的作用。我們可以把它理解為一個(gè)事件中心,我們所有事件的訂閱/發(fā)布都不能由訂閱方和發(fā)布方“私下溝通”,必須要委托這個(gè)事件中心幫我們實(shí)現(xiàn)。

class EventEmitter {
  constructor() {
    // handlers是一個(gè)map,用于存儲事件與回調(diào)之間的對應(yīng)關(guān)系
    this.handlers = {}
  }

  // on方法用于安裝事件監(jiān)聽器,它接受目標(biāo)事件名和回調(diào)函數(shù)作為參數(shù)
  on(eventName, cb) {
    // 先檢查一下目標(biāo)事件名有沒有對應(yīng)的監(jiān)聽函數(shù)隊(duì)列
    if (!this.handlers[eventName]) {
      // 如果沒有,那么首先初始化一個(gè)監(jiān)聽函數(shù)隊(duì)列
      this.handlers[eventName] = []
    }

    // 把回調(diào)函數(shù)推入目標(biāo)事件的監(jiān)聽函數(shù)隊(duì)列里去
    this.handlers[eventName].push(cb)
  }

  // emit方法用于觸發(fā)目標(biāo)事件,它接受事件名和監(jiān)聽函數(shù)入?yún)⒆鳛閰?shù)
  emit(eventName, ...args) {
    // 檢查目標(biāo)事件是否有監(jiān)聽函數(shù)隊(duì)列
    if (this.handlers[eventName]) {
      // 這里需要對 this.handlers[eventName] 做一次淺拷貝,主要目的是為了避免通過 once 安裝的監(jiān)聽器在移除的過程中出現(xiàn)順序問題
      const handlers = this.handlers[eventName].slice()
      // 如果有,則逐個(gè)調(diào)用隊(duì)列里的回調(diào)函數(shù)
      handlers.forEach((callback) => {
        callback(...args)
      })
    }
  }

  // 移除某個(gè)事件回調(diào)隊(duì)列里的指定回調(diào)函數(shù)
  off(eventName, cb) {
    const callbacks = this.handlers[eventName]
    const index = callbacks.indexOf(cb)
    if (index !== -1) {
      callbacks.splice(index, 1)
    }
  }

  // 為事件注冊單次監(jiān)聽器
  once(eventName, cb) {
    // 對回調(diào)函數(shù)進(jìn)行包裝,使其執(zhí)行完畢自動(dòng)被移除
    const wrapper = (...args) => {
      cb(...args)
      this.off(eventName, wrapper)
    }
    this.on(eventName, wrapper)
  }
}


// 使用方法
const eventBus = new EventEmitter()
eventBus.on('test', (val) => {
    console.log(val, "===test")
})
eventBus.emit('test', 21) // 輸出: 21,===test

總結(jié)

發(fā)布訂閱模式是一種常用的設(shè)計(jì)模式,它可以實(shí)現(xiàn)對象間的松耦合通信,支持異步處理和多對多的通信。它也有一些缺點(diǎn),比如可能會造成內(nèi)存泄漏、程序復(fù)雜性增加和信息不一致性。在使用發(fā)布訂閱模式時(shí),需要注意合理地設(shè)計(jì)發(fā)布者和訂閱者之間的關(guān)系,避免出現(xiàn)不必要的問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-742208.html

到了這里,關(guān)于js設(shè)計(jì)模式——發(fā)布訂閱模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 設(shè)計(jì)模式之訂閱發(fā)布模式

    訂閱發(fā)布模式(Publish-Subscribe Pattern)是一種行之有效的解耦框架與業(yè)務(wù)邏輯的方式,也是一種常見的觀察者設(shè)計(jì)模式,它被廣泛應(yīng)用于事件驅(qū)動(dòng)架構(gòu)中。 在這個(gè)模式中,發(fā)布者(或者說是主題)并不直接發(fā)送消息給訂閱者,而是通過調(diào)度中心(或者叫消息代理)來傳遞消息

    2024年02月06日
    瀏覽(84)
  • 設(shè)計(jì)模式之觀察者(發(fā)布訂閱)模式

    設(shè)計(jì)模式之觀察者(發(fā)布訂閱)模式

    觀察者模式定義了一種一對多的依賴關(guān)系,讓多個(gè)觀察者對象同事監(jiān)聽某一個(gè)主題對象。這個(gè)主題對象在狀態(tài)發(fā)生變化時(shí),會通知所有觀察者對象,使它們能夠自動(dòng)更新自己 觀察者模式主要解決的問題: 當(dāng)一個(gè)對象狀態(tài)發(fā)生改變后給其他的對象通知 觀察者的優(yōu)點(diǎn): 觀察者和

    2024年02月07日
    瀏覽(86)
  • 設(shè)計(jì)模式(四) —— 觀察者模式/發(fā)布訂閱模式,c和c++示例代碼

    往期地址: 設(shè)計(jì)模式(一)——簡單工廠模式 設(shè)計(jì)模式(二)——策略模式 設(shè)計(jì)模式(三)——裝飾模式 本期主題: 使用c和c++代碼,講解觀察者模式、發(fā)布訂閱模式 發(fā)布-訂閱模式是一種行為設(shè)計(jì)模式,它允許多個(gè)對象通過事件的發(fā)布和訂閱來進(jìn)行通信; 在這種模式中,

    2023年04月17日
    瀏覽(93)
  • 【JavaScript】手撕前端面試題:寄生組合式繼承 | 發(fā)布訂閱模式 | 觀察者模式

    ?????個(gè)人簡介:大三學(xué)生,一個(gè)不甘平庸的平凡人?? ??? NodeJS專欄:Node.js從入門到精通 ??? 博主的前端之路(源創(chuàng)征文一等獎(jiǎng)作品):前端之行,任重道遠(yuǎn)(來自大三學(xué)長的萬字自述) ??? TypeScript知識總結(jié):TypeScript從入門到精通(十萬字超詳細(xì)知識點(diǎn)總結(jié)) ??

    2023年04月08日
    瀏覽(96)
  • 前端設(shè)計(jì)模式:工廠方法模式、單例模式、訂閱模式、中介者模式

    工廠方法模式是一種創(chuàng)建型設(shè)計(jì)模式,它提供了一種將對象的創(chuàng)建與使用分離的方式。在工廠方法模式中,我們定義一個(gè)工廠接口,該接口聲明了一個(gè)用于創(chuàng)建對象的方法。具體的對象創(chuàng)建則由實(shí)現(xiàn)該接口的具體工廠類來完成。 工廠方法模式的核心思想是將對象的創(chuàng)建延遲到

    2024年02月12日
    瀏覽(91)
  • RabbitMQ學(xué)習(xí)——發(fā)布訂閱/fanout模式 & topic模式 & rabbitmq回調(diào)確認(rèn) & 延遲隊(duì)列(死信)設(shè)計(jì)

    RabbitMQ學(xué)習(xí)——發(fā)布訂閱/fanout模式 & topic模式 & rabbitmq回調(diào)確認(rèn) & 延遲隊(duì)列(死信)設(shè)計(jì)

    1.rabbitmq隊(duì)列方式的梳理,點(diǎn)對點(diǎn),一對多; 2.發(fā)布訂閱模式,交換機(jī)到消費(fèi)者,以郵箱和手機(jī)驗(yàn)證碼為例; 3.topic模式,根據(jù)規(guī)則決定發(fā)送給哪個(gè)隊(duì)列; 4.rabbitmq回調(diào)確認(rèn),setConfirmCallback和setReturnsCallback; 5.死信隊(duì)列,延遲隊(duì)列,創(chuàng)建方法,正常—死信,設(shè)置延遲時(shí)間; 點(diǎn)對

    2024年02月13日
    瀏覽(92)
  • RabbitMQ基礎(chǔ)(2)——發(fā)布訂閱/fanout模式 & topic模式 & rabbitmq回調(diào)確認(rèn) & 延遲隊(duì)列(死信)設(shè)計(jì)

    RabbitMQ基礎(chǔ)(2)——發(fā)布訂閱/fanout模式 & topic模式 & rabbitmq回調(diào)確認(rèn) & 延遲隊(duì)列(死信)設(shè)計(jì)

    1.rabbitmq隊(duì)列方式的梳理,點(diǎn)對點(diǎn),一對多; 2.發(fā)布訂閱模式,交換機(jī)到消費(fèi)者,以郵箱和手機(jī)驗(yàn)證碼為例; 3.topic模式,根據(jù)規(guī)則決定發(fā)送給哪個(gè)隊(duì)列; 4.rabbitmq回調(diào)確認(rèn),setConfirmCallback和setReturnsCallback; 5.死信隊(duì)列,延遲隊(duì)列,創(chuàng)建方法,正?!佬?,設(shè)置延遲時(shí)間; 點(diǎn)對

    2024年02月10日
    瀏覽(98)
  • 4.設(shè)計(jì)模式之后七種模式后11種模式命令訪問者迭代器發(fā)布訂閱中介者忘備錄解釋器狀態(tài)策略職責(zé)鏈和空模式

    4.設(shè)計(jì)模式之后七種模式后11種模式命令訪問者迭代器發(fā)布訂閱中介者忘備錄解釋器狀態(tài)策略職責(zé)鏈和空模式

    1.命令(command)模式 不知道命令接收者(對象)是誰,支持撤銷 (接受者 間接調(diào)用執(zhí)行 的具體行為) 命令調(diào)用者和接收者解耦 //只要實(shí)現(xiàn)命令接口即可 (就是客戶端給個(gè)命令,然后命令類傳給接收類執(zhí)行) 優(yōu)點(diǎn)和缺點(diǎn) 容易撤銷操作 命令隊(duì)列可以多線程操作 增加過多的命令類 空命令也

    2024年02月12日
    瀏覽(96)
  • 【前端知識】JavaScript——設(shè)計(jì)模式(工廠模式、構(gòu)造函數(shù)模式、原型模式)

    工廠模式是一種眾所周知的設(shè)計(jì)模式,廣泛應(yīng)用于軟件工程領(lǐng)域,用于抽象創(chuàng)建特定對象的過程。 優(yōu)點(diǎn):可以解決創(chuàng)建多個(gè)類似對象的問題 缺點(diǎn):沒有解決對象標(biāo)識問題(即新創(chuàng)建的對象是什么類型) 示例: 構(gòu)造函數(shù)模式與工廠模式相比,沒有顯式地創(chuàng)建對象,其屬性和方

    2024年02月15日
    瀏覽(54)
  • JavaScript 簡單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式

    JavaScript 簡單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式

    大家好,我是南木元元,熱衷分享有趣實(shí)用的文章。今天來聊聊設(shè)計(jì)模式中常用的觀察者模式和發(fā)布-訂閱模式。 觀察者模式定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都將得到通知。 如何理解這句話呢?來舉個(gè)生活中的例子

    2024年02月12日
    瀏覽(638)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包