node 訂閱發佈及實現

發佈訂閱模式 觀察者模式

發佈訂閱是主動的,來個例子,我有一個女友,要包,要車。等我有錢了,買包買車。這個過程當中,我要先訂閱買包買車,等有錢了在發佈。vue

觀察者被動執行。我先觀察你,你有變化了,我在變化,有點兒相似vue watch數組

發佈訂閱

例子1bash

先把想幹的事情存起來,當真的發生時候,依次將數組中的內容執行。對應關係以下:函數

{
  有錢:  [買包,買車]  
  女生失戀:  [哭,喝酒]  
}
複製代碼

代碼實現:ui

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('女生失戀');

複製代碼

模擬實現發佈訂閱this

  • 定義一個類
<!--新建文件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 了spa

// 訂閱
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 = {};
}
複製代碼

代碼:prototype

event.jscode

// 定義一個類
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('女生失戀'));
複製代碼
相關文章
相關標籤/搜索