欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript實(shí)現(xiàn)事件總線(xiàn)(Event?Bus)的方法詳解

 更新時(shí)間:2022年05月28日 08:38:03   作者:HPAN_  
Event?Bus?事件總線(xiàn),通常作為多個(gè)模塊間的通信機(jī)制,相當(dāng)于一個(gè)事件管理中心。本文將介紹如何在JavaScript中實(shí)現(xiàn)事件總線(xiàn),需要的可以參考一下

介紹

Event Bus 事件總線(xiàn),通常作為多個(gè)模塊間的通信機(jī)制,相當(dāng)于一個(gè)事件管理中心,一個(gè)模塊發(fā)送消息,其它模塊接受消息,就達(dá)到了通信的作用。

比如,Vue 組件間的數(shù)據(jù)傳遞可以使用一個(gè) Event Bus 來(lái)通信,也可以用作微內(nèi)核插件系統(tǒng)中的插件和核心通信。

原理

Event Bus 本質(zhì)上是采用了發(fā)布-訂閱的設(shè)計(jì)模式,比如多個(gè)模塊 A、BC 訂閱了一個(gè)事件 EventX,然后某一個(gè)模塊 X 在事件總線(xiàn)發(fā)布了這個(gè)事件,那么事件總線(xiàn)會(huì)負(fù)責(zé)通知所有訂閱者 AB、C,它們都能收到這個(gè)通知消息,同時(shí)還可以傳遞參數(shù)。

分析

如何使用 JavaScript 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單版本的 Event Bus

  • 首先構(gòu)造一個(gè) EventBus 類(lèi),初始化一個(gè)空對(duì)象用于存放所有的事件
  • 在接受訂閱時(shí),將事件名稱(chēng)作為 key 值,將需要在接受發(fā)布消息后執(zhí)行的回調(diào)函數(shù)作為 value 值,由于一個(gè)事件可能有多個(gè)訂閱者,所以這里的回調(diào)函數(shù)要存儲(chǔ)成列表
  • 在發(fā)布事件消息時(shí),從事件列表里取得指定的事件名稱(chēng)對(duì)應(yīng)的所有回調(diào)函數(shù),依次觸發(fā)執(zhí)行即可

以下是代碼詳細(xì)實(shí)現(xiàn),可以復(fù)制到谷歌瀏覽器控制臺(tái)直接運(yùn)行檢測(cè)效果。

代碼

class EventBus {
  constructor() {
    // 初始化事件列表
    this.eventObject = {};
  }
  // 發(fā)布事件
  publish(eventName) {
    // 取出當(dāng)前事件所有的回調(diào)函數(shù)
    const callbackList = this.eventObject[eventName];

    if (!callbackList) return console.warn(eventName + " not found!");

    // 執(zhí)行每一個(gè)回調(diào)函數(shù)
    for (let callback of callbackList) {
      callback();
    }
  }
  // 訂閱事件
  subscribe(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      this.eventObject[eventName] = [];
    }

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    this.eventObject[eventName].push(callback);
  }
}

// 測(cè)試
const eventBus = new EventBus();

// 訂閱事件eventX
eventBus.subscribe("eventX", () => {
  console.log("模塊A");
});
eventBus.subscribe("eventX", () => {
  console.log("模塊B");
});
eventBus.subscribe("eventX", () => {
  console.log("模塊C");
});

// 發(fā)布事件eventX
eventBus.publish("eventX");

// 輸出
> 模塊A
> 模塊B
> 模塊C

上面我們實(shí)現(xiàn)了最基礎(chǔ)的發(fā)布和訂閱功能,實(shí)際應(yīng)用中,還可能有更進(jìn)階的需求。

進(jìn)階

1. 如何在發(fā)送消息時(shí)傳遞參數(shù)

發(fā)布者傳入一個(gè)參數(shù)到 EventBus 中,在 callback 回調(diào)函數(shù)執(zhí)行的時(shí)候接著傳出參數(shù),這樣每一個(gè)訂閱者就可以收到參數(shù)了。

代碼

class EventBus {
  constructor() {
    // 初始化事件列表
    this.eventObject = {};
  }
  // 發(fā)布事件
  publish(eventName, ...args) {
    // 取出當(dāng)前事件所有的回調(diào)函數(shù)
    const callbackList = this.eventObject[eventName];

    if (!callbackList) return console.warn(eventName + " not found!");

    // 執(zhí)行每一個(gè)回調(diào)函數(shù)
    for (let callback of callbackList) {
      // 執(zhí)行時(shí)傳入?yún)?shù)
      callback(...args);
    }
  }
  // 訂閱事件
  subscribe(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      this.eventObject[eventName] = [];
    }

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    this.eventObject[eventName].push(callback);
  }
}

// 測(cè)試
const eventBus = new EventBus();

// 訂閱事件eventX
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊C", obj, num);
});

// 發(fā)布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);


// 輸出
> 模塊A {msg: 'EventX published!'} 1
> 模塊B {msg: 'EventX published!'} 1
> 模塊C {msg: 'EventX published!'} 1

2. 訂閱后如何取消訂閱

有時(shí)候訂閱者只想在某一個(gè)時(shí)間段訂閱消息,這就涉及帶取消訂閱功能。我們將對(duì)代碼進(jìn)行改造。

首先,要實(shí)現(xiàn)指定訂閱者取消訂閱,每一次訂閱事件時(shí),都生成唯一一個(gè)取消訂閱的函數(shù),用戶(hù)直接調(diào)用這個(gè)函數(shù),我們就把當(dāng)前訂閱的回調(diào)函數(shù)刪除。

// 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
const unSubscribe = () => {
  // 清除這個(gè)訂閱者的回調(diào)函數(shù)
  delete this.eventObject[eventName][id];
};

其次,訂閱的回調(diào)函數(shù)列表使換成對(duì)象結(jié)構(gòu)存儲(chǔ),為每一個(gè)回調(diào)函數(shù)設(shè)定一個(gè)唯一 id, 注銷(xiāo)回調(diào)函數(shù)的時(shí)候可以提高刪除的效率,如果還是使用數(shù)組的話(huà)需要使用 split 刪除,效率不如對(duì)象的 delete。

代碼

class EventBus {
  constructor() {
    // 初始化事件列表
    this.eventObject = {};
    // 回調(diào)函數(shù)列表的id
    this.callbackId = 0;
  }
  // 發(fā)布事件
  publish(eventName, ...args) {
    // 取出當(dāng)前事件所有的回調(diào)函數(shù)
    const callbackObject = this.eventObject[eventName];

    if (!callbackObject) return console.warn(eventName + " not found!");

    // 執(zhí)行每一個(gè)回調(diào)函數(shù)
    for (let id in callbackObject) {
      // 執(zhí)行時(shí)傳入?yún)?shù)
      callbackObject[id](...args);
    }
  }
  // 訂閱事件
  subscribe(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this.eventObject[eventName] = {};
    }

    const id = this.callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this.eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this.eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }
}

// 測(cè)試
const eventBus = new EventBus();

// 訂閱事件eventX
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊B", obj, num);
});
const subscriberC = eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊C", obj, num);
});

// 發(fā)布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);

// 模塊C取消訂閱
subscriberC.unSubscribe();

// 再次發(fā)布事件eventX,模塊C不會(huì)再收到消息了
eventBus.publish("eventX", { msg: "EventX published again!" }, 2);

// 輸出
> 模塊A {msg: 'EventX published!'} 1
> 模塊B {msg: 'EventX published!'} 1
> 模塊C {msg: 'EventX published!'} 1
> 模塊A {msg: 'EventX published again!'} 2
> 模塊B {msg: 'EventX published again!'} 2

3. 如何只訂閱一次

如果一個(gè)事件只發(fā)生一次,通常也只需要訂閱一次,收到消息后就不用再接受消息。

首先,我們提供一個(gè) subscribeOnce 的接口,內(nèi)部實(shí)現(xiàn)幾乎和 subscribe 一樣,只有一個(gè)地方有區(qū)別,在 callbackId 前面的加一個(gè)字符 d,用來(lái)標(biāo)示這是一個(gè)需要?jiǎng)h除的訂閱。

// 標(biāo)示為只訂閱一次的回調(diào)函數(shù)
const id = "d" + this.callbackId++;

然后,在執(zhí)行回調(diào)函數(shù)后判斷當(dāng)前回調(diào)函數(shù)的 id 有沒(méi)有標(biāo)示,決定我們是否需要?jiǎng)h除這個(gè)回調(diào)函數(shù)。

// 只訂閱一次的回調(diào)函數(shù)需要?jiǎng)h除
if (id[0] === "d") {
  delete callbackObject[id];
}

代碼

class EventBus {
  constructor() {
    // 初始化事件列表
    this.eventObject = {};
    // 回調(diào)函數(shù)列表的id
    this.callbackId = 0;
  }
  // 發(fā)布事件
  publish(eventName, ...args) {
    // 取出當(dāng)前事件所有的回調(diào)函數(shù)
    const callbackObject = this.eventObject[eventName];

    if (!callbackObject) return console.warn(eventName + " not found!");

    // 執(zhí)行每一個(gè)回調(diào)函數(shù)
    for (let id in callbackObject) {
      // 執(zhí)行時(shí)傳入?yún)?shù)
      callbackObject[id](...args);

      // 只訂閱一次的回調(diào)函數(shù)需要?jiǎng)h除
      if (id[0] === "d") {
        delete callbackObject[id];
      }
    }
  }
  // 訂閱事件
  subscribe(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this.eventObject[eventName] = {};
    }

    const id = this.callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this.eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this.eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 只訂閱一次
  subscribeOnce(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this.eventObject[eventName] = {};
    }

    // 標(biāo)示為只訂閱一次的回調(diào)函數(shù)
    const id = "d" + this.callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this.eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this.eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }
}

// 測(cè)試
const eventBus = new EventBus();

// 訂閱事件eventX
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊A", obj, num);
});
eventBus.subscribeOnce("eventX", (obj, num) => {
  console.log("模塊B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊C", obj, num);
});

// 發(fā)布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);

// 再次發(fā)布事件eventX,模塊B只訂閱了一次,不會(huì)再收到消息了
eventBus.publish("eventX", { msg: "EventX published again!" }, 2);

// 輸出
> 模塊A {msg: 'EventX published!'} 1
> 模塊C {msg: 'EventX published!'} 1
> 模塊B {msg: 'EventX published!'} 1
> 模塊A {msg: 'EventX published again!'} 2
> 模塊C {msg: 'EventX published again!'} 2

4. 如何清除某個(gè)事件或者所有事件

我們還希望通過(guò)一個(gè) clear 的操作來(lái)將指定事件的所有訂閱清除掉,這個(gè)通常在一些組件或者模塊卸載的時(shí)候用到。

  // 清除事件
  clear(eventName) {
    // 未提供事件名稱(chēng),默認(rèn)清除所有事件
    if (!eventName) {
      this.eventObject = {};
      return;
    }

    // 清除指定事件
    delete this.eventObject[eventName];
  }

和取消訂閱的邏輯相似,只不過(guò)這里統(tǒng)一處理了。

代碼

class EventBus {
  constructor() {
    // 初始化事件列表
    this.eventObject = {};
    // 回調(diào)函數(shù)列表的id
    this.callbackId = 0;
  }
  // 發(fā)布事件
  publish(eventName, ...args) {
    // 取出當(dāng)前事件所有的回調(diào)函數(shù)
    const callbackObject = this.eventObject[eventName];

    if (!callbackObject) return console.warn(eventName + " not found!");

    // 執(zhí)行每一個(gè)回調(diào)函數(shù)
    for (let id in callbackObject) {
      // 執(zhí)行時(shí)傳入?yún)?shù)
      callbackObject[id](...args);

      // 只訂閱一次的回調(diào)函數(shù)需要?jiǎng)h除
      if (id[0] === "d") {
        delete callbackObject[id];
      }
    }
  }
  // 訂閱事件
  subscribe(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this.eventObject[eventName] = {};
    }

    const id = this.callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this.eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this.eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 只訂閱一次
  subscribeOnce(eventName, callback) {
    // 初始化這個(gè)事件
    if (!this.eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this.eventObject[eventName] = {};
    }

    // 標(biāo)示為只訂閱一次的回調(diào)函數(shù)
    const id = "d" + this.callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this.eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this.eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 清除事件
  clear(eventName) {
    // 未提供事件名稱(chēng),默認(rèn)清除所有事件
    if (!eventName) {
      this.eventObject = {};
      return;
    }

    // 清除指定事件
    delete this.eventObject[eventName];
  }
}

// 測(cè)試
const eventBus = new EventBus();

// 訂閱事件eventX
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模塊C", obj, num);
});

// 發(fā)布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);

// 清除
eventBus.clear("eventX");

// 再次發(fā)布事件eventX,由于已經(jīng)清除,所有模塊都不會(huì)再收到消息了
eventBus.publish("eventX", { msg: "EventX published again!" }, 2);

// 輸出
> 模塊A {msg: 'EventX published!'} 1
> 模塊B {msg: 'EventX published!'} 1
> 模塊C {msg: 'EventX published!'} 1
> eventX not found!

5. TypeScript 版本

鑒于現(xiàn)在 TypeScript 已經(jīng)被大規(guī)模采用,尤其是大型前端項(xiàng)目,我們簡(jiǎn)要的改造為一個(gè) TypeScript 版本

可以復(fù)制以下代碼到 TypeScript Playground 體驗(yàn)運(yùn)行效果

代碼

interface ICallbackList {
  [id: string]: Function;
}

interface IEventObject {
  [eventName: string]: ICallbackList;
}

interface ISubscribe {
  unSubscribe: () => void;
}

interface IEventBus {
  publish<T extends any[]>(eventName: string, ...args: T): void;
  subscribe(eventName: string, callback: Function): ISubscribe;
  subscribeOnce(eventName: string, callback: Function): ISubscribe;
  clear(eventName: string): void;
}

class EventBus implements IEventBus {
  private _eventObject: IEventObject;
  private _callbackId: number;
  constructor() {
    // 初始化事件列表
    this._eventObject = {};
    // 回調(diào)函數(shù)列表的id
    this._callbackId = 0;
  }
  // 發(fā)布事件
  publish<T extends any[]>(eventName: string, ...args: T): void {
    // 取出當(dāng)前事件所有的回調(diào)函數(shù)
    const callbackObject = this._eventObject[eventName];

    if (!callbackObject) return console.warn(eventName + " not found!");

    // 執(zhí)行每一個(gè)回調(diào)函數(shù)
    for (let id in callbackObject) {
      // 執(zhí)行時(shí)傳入?yún)?shù)
      callbackObject[id](...args);

      // 只訂閱一次的回調(diào)函數(shù)需要?jiǎng)h除
      if (id[0] === "d") {
        delete callbackObject[id];
      }
    }
  }
  // 訂閱事件
  subscribe(eventName: string, callback: Function): ISubscribe {
    // 初始化這個(gè)事件
    if (!this._eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this._eventObject[eventName] = {};
    }

    const id = this._callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this._eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this._eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this._eventObject[eventName]).length === 0) {
        delete this._eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 只訂閱一次
  subscribeOnce(eventName: string, callback: Function): ISubscribe {
    // 初始化這個(gè)事件
    if (!this._eventObject[eventName]) {
      // 使用對(duì)象存儲(chǔ),注銷(xiāo)回調(diào)函數(shù)的時(shí)候提高刪除的效率
      this._eventObject[eventName] = {};
    }

    // 標(biāo)示為只訂閱一次的回調(diào)函數(shù)
    const id = "d" + this._callbackId++;

    // 存儲(chǔ)訂閱者的回調(diào)函數(shù)
    // callbackId使用后需要自增,供下一個(gè)回調(diào)函數(shù)使用
    this._eventObject[eventName][id] = callback;

    // 每一次訂閱事件,都生成唯一一個(gè)取消訂閱的函數(shù)
    const unSubscribe = () => {
      // 清除這個(gè)訂閱者的回調(diào)函數(shù)
      delete this._eventObject[eventName][id];

      // 如果這個(gè)事件沒(méi)有訂閱者了,也把整個(gè)事件對(duì)象清除
      if (Object.keys(this._eventObject[eventName]).length === 0) {
        delete this._eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 清除事件
  clear(eventName: string): void {
    // 未提供事件名稱(chēng),默認(rèn)清除所有事件
    if (!eventName) {
      this._eventObject = {};
      return;
    }

    // 清除指定事件
    delete this._eventObject[eventName];
  }
}

// 測(cè)試
interface IObj {
  msg: string;
}

type PublishType = [IObj, number];

const eventBus = new EventBus();

// 訂閱事件eventX
eventBus.subscribe("eventX", (obj: IObj, num: number, s: string) => {
  console.log("模塊A", obj, num);
});
eventBus.subscribe("eventX", (obj: IObj, num: number) => {
  console.log("模塊B", obj, num);
});
eventBus.subscribe("eventX", (obj: IObj, num: number) => {
  console.log("模塊C", obj, num);
});

// 發(fā)布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);

// 清除
eventBus.clear("eventX");

// 再次發(fā)布事件eventX,由于已經(jīng)清除,所有模塊都不會(huì)再收到消息了
eventBus.publish<PublishType>("eventX", { msg: "EventX published again!" }, 2);

// 輸出
[LOG]: "模塊A",  {
  "msg": "EventX published!"
},  1
[LOG]: "模塊B",  {
  "msg": "EventX published!"
},  1
[LOG]: "模塊C",  {
  "msg": "EventX published!"
},  1
[WRN]: "eventX not found!"

6. 單例模式

在實(shí)際使用過(guò)程中,往往只需要一個(gè)事件總線(xiàn)就能滿(mǎn)足需求,這里有兩種情況,保持在上層實(shí)例中單例和全局單例。

1.保持在上層實(shí)例中單例

將事件總線(xiàn)引入到上層實(shí)例使用,只需要保證在一個(gè)上層實(shí)例中只有一個(gè) EventBus,如果上層實(shí)例有多個(gè),意味著有多個(gè)事件總線(xiàn),但是每個(gè)上層實(shí)例管控自己的事件總線(xiàn)。

首先在上層實(shí)例中建立一個(gè)變量用來(lái)存儲(chǔ)事件總線(xiàn),只在第一次使用時(shí)初始化,后續(xù)其他模塊使用事件總線(xiàn)時(shí)直接取得這個(gè)事件總線(xiàn)實(shí)例。

代碼

// 上層實(shí)例
class LWebApp {
  private _eventBus?: EventBus;

  constructor() {}

  public getEventBus() {
    // 第一次初始化
    if (this._eventBus == undefined) {
      this._eventBus = new EventBus();
    }

    // 后續(xù)每次直接取唯一一個(gè)實(shí)例,保持在LWebApp實(shí)例中單例
    return this._eventBus;
  }
}

// 使用
const eventBus = new LWebApp().getEventBus();

2.全局單例

有時(shí)候我們希望不管哪一個(gè)模塊想使用我們的事件總線(xiàn),我們都想這些模塊使用的是同一個(gè)實(shí)例,這就是全局單例,這種設(shè)計(jì)能更容易統(tǒng)一管理事件。

寫(xiě)法同上面的類(lèi)似,區(qū)別是要把 _eventBus 和 getEventBus 轉(zhuǎn)為靜態(tài)屬性。使用時(shí)無(wú)需實(shí)例化 EventBusTool 工具類(lèi),直接使用靜態(tài)方法就行了。

代碼

// 上層實(shí)例
class EventBusTool {
  private static _eventBus?: EventBus;

  constructor() {}

  public static getEventBus(): EventBus {
    // 第一次初始化
    if (this._eventBus == undefined) {
      this._eventBus = new EventBus();
    }

    // 后續(xù)每次直接取唯一一個(gè)實(shí)例,保持全局單例
    return this._eventBus;
  }
}

// 使用
const eventBus = EventBusTool.getEventBus();

總結(jié)

以上是小編對(duì) Event Bus 的一些理解,基本上實(shí)現(xiàn)了想要的效果。通過(guò)自己動(dòng)手實(shí)現(xiàn)一遍發(fā)布訂閱模式,也加深了對(duì)經(jīng)典設(shè)計(jì)模式的理解。其中還有很多不足和需要優(yōu)化的地方。

到此這篇關(guān)于JavaScript實(shí)現(xiàn)事件總線(xiàn)(Event Bus)的方法詳解的文章就介紹到這了,更多相關(guān)JavaScript事件總線(xiàn)Event Bus內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論