发布订阅模式

EventEmitter 实现

class EventEmitter {
  constructor() {
    this.events = {}; // {type: [fn1, fn2]}
  }
  emit(type, ...args) {
    const listeners = this.events[type];
    if (listeners) {
      for (let listener of listeners) {
        listener(...args);
      }
    }
  }
  on(type, listener) {
    if (typeof listener !== "function") {
      throw new TypeError("listener is not function");
    }
    this.events[type] = this.events[type] || [];
    this.events[type].push(listener);
  }
  off(type, listener) {
    const listeners = this.events[type];
    if (listeners) {
      this.events[type] = listeners.filter((cb) => cb !== listener);
    }
  }
  once(type, listener) {
    const warpper = (...args) => {
      listener(...args);
      this.off(type, warpper);
    };
    this.on(type, warpper);
  }
}

const _event = new EventEmitter();

// 订阅 click 事件
_event.on("click", (data) => console.log("常规订阅:", data));

// 一次性订阅
_event.once("click", (data) => console.log("仅触发一次:", data));

// 触发事件
_event.emit("click", { id: 1 }); // 输出:常规订阅 和 仅触发一次
_event.emit("click", { id: 2 }); // 仅输出:常规订阅

// 取消订阅
const callback = (data) => console.log("待取消的订阅", data);
_event.on("click", callback);
_event.off("click", callback);

_event.emit("click", { id: 3 });

// 常规订阅: { id: 1 }
// 仅触发一次: { id: 1 }
// 常规订阅: { id: 2 }
// 常规订阅: { id: 3 }

应用场景

  • 组件通信
  • 事件总线

常见面试题

  1. 什么是发布订阅模式?
  2. 手写 EventEmitter?
  3. 发布订阅和观察者模式的区别?