Skip to content

发布订阅模式

发布订阅模式是一种常见的设计模式,通过事件的方式来完成对象间通信,在发布订阅模式里,发布者和订阅者是完全解耦的。 发布者并不会直接通知订阅者,而是将消息通知给控制中枢(消息代理),订阅者通过中枢订阅主题。当发布者发布一条消息后, 控制中枢会分发给订阅该主题的所有订阅者。像浏览器的事件系统,Vue 的事件都使用了该模式。

js
class Publisher {
  constructor() {
    this.topics = {};
  }

  subscribe(k, cb) {
    if (!this.topics[k]) {
      this.topics[k] = [];
    }
    this.topics[k].push(cb);
  }

  publish(k, ...args) {
    if (Array.isArray(this.topics[k])) {
      this.topics[k].forEach(cb => cb.apply(null, args));
    }
  }

  unsubscribe(k) {
    this.topics[k].length = [];
  }
}

const publisher = new Publisher();

publisher.subscribe('name', name => {
  console.log('name is ', name);
});

publisher.subscribe('name', name => {
  console.log('name1 is ', name);
});

publisher.subscribe('age', age => {
  console.log('age is ', age);
});

publisher.subscribe('age', age => {
  console.log('age1 is ', age);
});

publisher.publish('name', 'limy'); //name is  limy; name1 is  limy
publisher.publish('age', '18'); // age is  18; age1 is  18

publisher.unsubscribe('age');

publisher.publish('name', 'limy'); // name is  limy; name1 is  limy
publisher.publish('age', '18'); //

class EventEmitter {
  constructor() {
    this._events = {};
  }
  on(k, handler) {
    if (!this._events[k]) {
      this._events[k] = [];
    }
    this._events[k].push(handler);
  }

  off(k, handler) {
    if (!Array.isArray(this._events[k])) return;
    const idx = this._events[k].indexOf(handler);
    if (idx !== -1) {
      this._events[k].splice(idx, 1);
    }
  }

  emit(k, ...args) {
    if (!Array.isArray(this._events[k])) return;
    this._events[k].forEach(handler => handler.apply(this, args));
  }

  once(k, handler) {
    if (!this._events[k]) {
      this._events[k] = [];
    }
    const fn = (...args) => {
      handler.apply(this, args);
      this.off(k, fn);
    };
    this.on(k, fn);
  }
}

const events = new EventEmitter();
console.log(`------------------EventEmitter-----------------`);

function showName(name) {
  console.log(`showName `, name);
}

events.on('name', name => console.log('name is ', name));
events.on('name', showName);
events.once('name', name => console.log('once name is ', name));

events.emit('name', 'argName'); // name is  argName; showName  argName; once name is  argName
events.off('name', showName);
events.emit('name', 'argName'); // name is  argName