阅读 217

node 订阅发布及实现

发布订阅模式 观察者模式

发布订阅是主动的,来个例子,我有一个女朋友,要包,要车。等我有钱了,买包买车。这个过程中,我要先订阅买包买车,等有钱了在发布。

观察者被动执行。我先观察你,你有变化了,我在变化,有点儿类似vue watch

发布订阅

例子1

先把想干的事情存起来,当真的发生时候,依次将数组中的内容执行。对应关系如下:

{
  有钱:  [买包,买车]  
  女生失恋:  [哭,喝酒]  
}
复制代码

代码实现:

let EventEmitter = require('events');
let util = require('util');
// 定义一个类
function Girl() { 

}

// 继承共有方法
util.inherits(Girl, EventEmitter);

let girl = new Girl();

let cry = () => {
  console.log('哭');
}
let drink = () => {
  console.log('喝酒');
}

// 绑定对应方法
girl.on('女生失恋', cry);
girl.on('女生失恋', drink);

// 默认情况下是不执行的
// 触发执行
girl.emit('女生失恋');

复制代码

模拟实现发布订阅

  • 定义一个类
<!--新建文件events.js-->
// 定义一个类
function EventEmitter() {

}

// 导出
module.exports = EventEmitter;

复制代码
  • 定义好 on 和 emit 方法
// 定义一个类
function EventEmitter() {

}

// 订阅
EventEmitter.prototype.on = function() {

}

// 发布
EventEmitter.prototype.emit = function() {

}

// 导出
module.exports = EventEmitter;

复制代码
  • 首先先维护一个对象,对象对应 { '女生失恋': ['喝酒fn', '哭fn'] }
// 定义一个类
function EventEmitter() {
  // 维护一个对象
  // {
  //   '女生失恋': ['哭', '喝酒']
  // }
  this._events = {};
}

// 订阅
EventEmitter.prototype.on = function(type, callback) {
  // 如果取不到_events 默认给空对象
  if (!this._events){
    this._events = {};
  }
  // 对象中存在
  if (this._events[type]) {
    this._events[type].push(callback);
  } else {
    this._events[type] = [callback];
  }
}
复制代码
  • 当执行 emit 时候将数组中的函数依次执行
// 发布
EventEmitter.prototype.emit = function(type) {
  // 存在数组
  if (this._events[type]) {
    this._events[type].forEach(fn => {
      // 此处的 fn 就是 喝酒, 哭
      fn();
    });
  }
}
复制代码
  • 解绑方法
EventEmitter.prototype.removeListener = function(type, callback) {
  // 找到数组中对应方法移除。
  if (this._events[type]) {
    this._events[type] = this._events[type].filter(fn => {
      return fn != callback;
    })
  }
}

// 外界调用
// 解绑事件
girl.removeListener('女生失恋', cry);
复制代码
  • 添加 newListener 方法获取当前监听什么事件名字。

当前监听的如果不是 newListener 时候。执行 newListener 方法把当前 type 传递给回调函数,这样外界就可以获取 type 了

// 订阅
EventEmitter.prototype.on = function(type, callback) {
  if (type !== 'newListener') {
    this._events['newListener'].forEach(fn => {
      fn(type);
    })
  }
  // 如果取不到_events 默认给空对象
  if (!this._events){
    this._events = {};
  }
  // 对象中存在
  if (this._events[type]) {
    this._events[type].push(callback);
  } else {
    this._events[type] = [callback];
  }
}

// 外界调用
girl.on('newListener', (type) => {
  console.log(type);
})
复制代码
  • 其他方法
// 默认最大监听
EventEmitter.defaultMaxListener = 10;

// 设置最大监听
EventEmitter.prototype.setMaxListeners = function(count) {
  this._count = count;
}
// 获取最大监听
EventEmitter.prototype.getMaxListeners = function(count) {
  return this._count || EventEmitter.defaultMaxListener;
}
// 获取 eventName
EventEmitter.prototype.eventNames = function() {
  return Object.keys(this._events);
}
// 获取监听方法
EventEmitter.prototype.listeners = function(type) {
  return this._events[type];
}

// 移除所有监听
EventEmitter.prototype.removeAllListeners = function(type) {
  if (type) {
   return this._events[type] = [];
  };
  this._events = {};
}
复制代码

代码:

event.js

// 定义一个类
function EventEmitter() {
  // 维护一个对象
  // {
  //   '女生失恋': ['哭', '喝酒']
  //   'newListener': []
  // }
  this._events = {};
}

// 订阅
EventEmitter.prototype.addListener = EventEmitter.prototype.on = function(type, callback) {
  // 如果取不到_events 默认给空对象
  if (!this._events) {
    this._events = Object.create(null);
  }
  if (type !== 'newListener' && this._events['newListener'] && this._events['newListener'].length) {
    this._events['newListener'].forEach(fn => {
      fn(type);
    })
  }
  // 对象中存在
  if (this._events[type]) {
    this._events[type].push(callback);
  } else {
    this._events[type] = [callback];
  }
  // 如果超限制提示错误
  if (this._events[type].length === this.getMaxListeners()) {
    console.warn('memory link detected');
  }
}

// 发布
EventEmitter.prototype.emit = function(type, ...args) {
  // 存在数组
  if (this._events[type]) {
    this._events[type].forEach(fn => {
      // 此处的 fn 就是 喝酒, 哭
      fn(...args);
    });
  }
}

EventEmitter.prototype.removeListener = function(type, callback) {
  // 找到数组中对应方法移除。
  if (this._events[type]) {
    this._events[type] = this._events[type].filter(fn => {
      return fn != callback && fn.l !== callback;
    })
  }
}
// 默认最大监听
EventEmitter.defaultMaxListener = 10;

// 设置最大监听
EventEmitter.prototype.setMaxListeners = function(count) {
  this._count = count;
}
// 获取最大监听
EventEmitter.prototype.getMaxListeners = function(count) {
  return this._count || EventEmitter.defaultMaxListener;
}
// 获取 eventName
EventEmitter.prototype.eventNames = function() {
  return Object.keys(this._events);
}
// 获取监听方法
EventEmitter.prototype.listeners = function(type) {
  return this._events[type];
}

// 移除所有监听
EventEmitter.prototype.removeAllListeners = function(type) {
  if (type) {
   return this._events[type] = [];
  };
  this._events = {};
}

// once 先绑定 wrap 函数当执行完后从数组中删除。
EventEmitter.prototype.once = function(type, callback) {
  // 添加一个包裹函数。
  let wrap = (...args) => {
    callback(...args);
    this.removeListener(type, wrap);
  }
  // 将callback保存在 wrap.l上
  wrap.l = callback;
  this.on(type, wrap);
}

// 导出
module.exports = EventEmitter;

复制代码

调用:

let EventEmitter = require('./events');
let util = require('util');
// 定义一个类
function Girl() { 
  // EventEmitter.call(this);
}

// 继承共有方法
util.inherits(Girl, EventEmitter);

let girl = new Girl();

let cry = (a, b) => {
  console.log('哭', a, b);
}
let drink = (a, b) => {
  console.log('喝酒', a, b);
}

// girl.setMaxListeners(1);

// console.log(girl.getMaxListeners());

girl.on('newListener', (type) => {
  // console.log(type, '哈哈哈');
})

// 绑定对应方法
girl.once('女生失恋', cry);
// girl.on('女生失恋', drink);

// 解绑事件
// girl.removeListener('女生失恋', cry);

// 默认情况下是不执行的
// 触发执行
girl.emit('女生失恋', 1, 2);
girl.emit('女生失恋');
girl.emit('女生失恋');
// 获取最大监听
// console.log(EventEmitter.defaultMaxListener);

// 获取 eventNames [ 'newListener', '女生失恋' ]
// console.log(girl.eventNames());

console.log(girl.listeners('女生失恋'));
复制代码