node核心模块之Event

143 阅读2分钟

events 的基本概念

我们知道,node 是一种非阻塞式 I/O 的模型,它的特点是事件驱动,所以 node 中有个非常典型的核心模块,这个模块非常常用,叫 events,它是一个类,里面主要实现了发布订阅的功能。

 // 核心模块,可以直接引用的模块,不需要下载包或者自己写
 const EventEmitter = require('events');

 // 发布订阅 ->  on 订阅  emit 发布  off 取消订阅
 const events = new EventEmitter();

模块的订阅发布(on、emit)

 events.on('女孩失恋了', function(data) {
   console.log('哭', data);
 });
 
 events.on('女孩失恋了', function(data) {
   console.log('吃', data);
 });
 
 events.emit('女孩失恋了', '她不够可爱');

// 哭 她不够可爱
// 吃 她不够可爱

process.nextTick 的使用场景

如果我想注册上,马上就触发怎么办,上 process.nextTick ~

// nextTick 可以解决异步调用的问题,而且方式优于 promise.then
 process.nextTick(() => {
  events.emit('女孩失恋了', '她不够可爱');
 });
 
 events.on('女孩失恋了', function(data) {
   console.log('哭', data);
 });
 
 events.on('女孩失恋了', function(data) {
   console.log('吃', data);
 });

off 取消订阅

我们可以使用 off 取消订阅

 const cry = function(data) {
  console.log('哭', data);
 }
 
 events.on('女孩失恋了', cry);
 
// 必须传入事件名 + 回调方法名
 events.off('女孩失恋了', cry); 

once 绑定一次

events.on('女孩失恋了', function(data) {
  console.log('吃', data);
});

events.once('女孩失恋了', function(data) {
  console.log('逛街', data);
});
 
events.emit('女孩失恋了', '触发第一次');
events.emit('女孩失恋了', '触发第二次');

// 吃 触发第一次
// 逛街 触发第一次
// 吃 触发第二次

手动实现 events 模块的 on off once emit

// 手动实现 events 模块的 on off once emit
function EventEmitter() {
  this._events = {};
}

EventEmitter.prototype.on = function(eventName, cb) {
  // 考虑继承的情况,this 上如果没有 _events,手动创建
  if (!this._events) this._events = {};
  const callbacks = this._events[eventName] || [];

  callbacks.push(cb);
  this._events[eventName] = callbacks;
}

EventEmitter.prototype.emit = function(eventName, ...args) {
  // 考虑继承的情况,this 上如果没有 _events,手动创建
  const callbacks = this._events[eventName];
  if (callbacks) {
    callbacks.forEach(cb => cb(...args));
  }
}

EventEmitter.prototype.off = function(eventName, cb) {
  // 考虑继承的情况,this 上如果没有 _events,手动创建
  if (!this._events) this._events = {};

  if ( this._events[eventName]) {
    this._events[eventName] = this._events[eventName].filter(fn => {
      return fn !== cb && fn.l !== cb;
    });
  }
}

EventEmitter.prototype.once = function(eventName, cb) {
  // 重写原 cb 方法
  const one = (...args) => {
    cb(...args);
    // 执行完毕就删除订阅
    this.off(eventName, one);
  }

  // 为了能 off 掉 once 订阅的事件 这里建立映射关系
  // 因为 once 绑定的是 one 函数,而不是 cb
  one.l = cb; 

  // 先绑定 这里不能通过 bind(this) 去重写 one 方法中的 this
  // bind(this) 每次返回的是一个新函数
  this.on(eventName, one);
}

module.exports = EventEmitter;
// 测试代码
 // 核心模块,可以直接引用的模块,不需要下载包或者自己写
 const EventEmitter = require('./events');

 // 发布订阅 ->  on 订阅  emit 发布
 const events = new EventEmitter();

 const eat = function(data) {
   console.log('吃', data);
 }

 events.on('女孩失恋了', eat);
 events.off('女孩失恋了', eat);
 events.once('女孩失恋了', eat);
 events.off('女孩失恋了', eat);
 
 events.once('女孩失恋了', function(data) {
  console.log('逛街', data);
});
 
events.emit('女孩失恋了', '触发第一次');
events.emit('女孩失恋了', '触发第二次');