pfan123/Articles

EventEmitter 理解

Opened this issue · 0 comments

EventEmitter 事件发射器是一种发布,订阅模式,是event 模块提供的一个对象,用来注册事件可触发事件。Node 中的异步操作都是基于EventEmitter 来实现的。

EventEmitter主要API

  • emitter.on(event, listener) 注册一个事件
  • emitter.once(event, listener) 注册一个一次性的事件,触发后就被抹掉
  • emitter.removeListener(event, listener) 在时间队列中剔除某一个事件
  • emitter.removeAllListeners([event]) 删除整个事件队列,或多个事件
  • emitter.listeners(event) 返回某些事件 emitter.emit(event, [arg1], [arg2], […]) 触发事件,可传入具体参数

EventEmitter使用方式

  • 实例化获取EventEmitter
const events = require('events');
 
const emitter = new events.EventEmitter();
 
// 绑定sayHi事件,可以绑定多个同名事件,触发时会顺序触发
emitter.on('sayHi', function(someone){
    console.log("我是", someone)
})
emitter.on('sayHi', function(someone){
    console.log("我就是", someone)
})
 
// 触发sayHi事件
emitter.emit('sayHi', 'pfan');
 
// 我是pfan
// 我就是pfan

继承获取事件对象的方法

const util = require('util');
 
const events = require('events');
 
// 创建自定义对象
let Cat = function (name) {
    this.name = name;
}
 
// 继承events.EventEmitter
util.inherits(Cat, events.EventEmitter);
 
// 创建自定义对象实例
let Tom = new Cat('Tom');
 
// 绑定sayHiTo事件
Tom.on('sayHi', function(someone){
    // this指向实例Tom
    console.log(this.name," sayHiTo ", someone)
})
 
Tom.emit('sayHiTo', 'pfan')
 
// 输出
 
// Tom sayHiTo pfan

Node.js中大部分的模块,都继承自Event模块,来异步操作处理如request、stream

常见Event Emitter工具库实现

可以采用现有的成熟框架,通过继承即可食用:

Component: component/emitter
Bower or standalone: Wolfy87/EventEmitter

EventEmitter的实现原理

EventEmitter实现并不难,可以实现一个简单的版本,加深理解。具备以下基本功能:

  • on: 为特定事件添加监听器
  • off: 为特定事件移除监听器
  • emit: 触发特定事件
  • once: 注册只执行一次的监听器
function Emitter(){
  this.events = {}
}

Emitter.prototype.on = function(type, listener){
  // 在事件对象中加入新的属性
  // 确保新的属性以数组的形式保存
  this.events[type] = this.events[type] || [];
  // 在数组中加入事件处理函数
  this.events[type].push(listener);
}

Emitter.prototype.off = function(type, listener){
	if(this.events && this.events[type]){
		delete this.events[type]
		listener(...arguments)
	}
}

Emitter.prototype.once = function(type, listener){
	let self = this
	this.on(type, function(){
		self.off(type)
		listener(...arguments)
	})
}

Emitter.prototype.emit = function(type, arg){
  if(this.events[type]) {// 如果事件对象中含有该属性
    this.events[type].forEach(function(listener){
      listener(arg)
    })
  }
}
module.exports = Emitter;

component/emitter 源码分析

/**
 * 使用 `Emitter` 方式
 */
var Emitter = require('emitter');
var emitter = new Emitter;
emitter.emit('something');

on(event, listener)
为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。

emit(event, [arg1], [arg2], [...])
按参数的顺序执行每个监听器,如果事件有注册监听返回 true,否则返回 false。

/**
 * 使用 `Emitter` 方式
 */


/**
 * 设置导出 `Emitter` 类
 */

if (typeof module !== 'undefined') {
  module.exports = Emitter;
}

/**
 * Initialize a new `Emitter`.
 *
 * @api public
 */

function Emitter(obj) {
  if (obj) return mixin(obj);
};

/**
 * Mixin the emitter properties.
 * 浅拷贝 Emitter.prototype
 * @param {Object} obj
 * @return {Object}
 * @api private
 */

function mixin(obj) {
  for (var key in Emitter.prototype) {
    obj[key] = Emitter.prototype[key];
  }
  return obj;
}

/**
 * Listen on the given `event` with `fn`.
 * 事件只执行一次
 * @param {String} event
 * @param {Function} fn
 * @return {Emitter}
 * @api public
 */

Emitter.prototype.on =
Emitter.prototype.addEventListener = function(event, fn){
  this._callbacks = this._callbacks || {};
  (this._callbacks['$' + event] = this._callbacks['$' + event] || [])
    .push(fn);
  return this;
};

/**
 * Adds an `event` listener that will be invoked a single
 * time then automatically removed.
 *
 * @param {String} event
 * @param {Function} fn
 * @return {Emitter}
 * @api public
 */

Emitter.prototype.once = function(event, fn){
  function on() {
    this.off(event, on);
    fn.apply(this, arguments);
  }

  on.fn = fn;
  this.on(event, on);
  return this;
};

/**
 * Remove the given callback for `event` or all
 * registered callbacks.
 * 移除注册的监听器
 * @param {String} event
 * @param {Function} fn
 * @return {Emitter}
 * @api public
 */

Emitter.prototype.off =
Emitter.prototype.removeListener =
Emitter.prototype.removeAllListeners =
Emitter.prototype.removeEventListener = function(event, fn){
  this._callbacks = this._callbacks || {};

  // all
  if (0 == arguments.length) {
    this._callbacks = {};
    return this;
  }

  // specific event
  var callbacks = this._callbacks['$' + event];
  if (!callbacks) return this;

  // remove all handlers
  if (1 == arguments.length) {
    delete this._callbacks['$' + event];
    return this;
  }

  // remove specific handler
  var cb;
  for (var i = 0; i < callbacks.length; i++) {
    cb = callbacks[i];
    if (cb === fn || cb.fn === fn) {
      callbacks.splice(i, 1);
      break;
    }
  }
  return this;
};

/**
 * Emit `event` with the given args.
 * 事件发射告诉监听器开始执行
 * @param {String} event
 * @param {Mixed} ...
 * @return {Emitter}
 */

Emitter.prototype.emit = function(event){
  this._callbacks = this._callbacks || {};
  var args = [].slice.call(arguments, 1)
    , callbacks = this._callbacks['$' + event];

  if (callbacks) {
    callbacks = callbacks.slice(0);
    for (var i = 0, len = callbacks.length; i < len; ++i) {
      callbacks[i].apply(this, args);
    }
  }

  return this;
};

/**
 * Return array of callbacks for `event`.
 * 返回监听
 * @param {String} event
 * @return {Array}
 * @api public
 */

Emitter.prototype.listeners = function(event){
  this._callbacks = this._callbacks || {};
  return this._callbacks['$' + event] || [];
};

/**
 * Check if this emitter has `event` handlers.
 * 检测是否含有监听器
 * @param {String} event
 * @return {Boolean}
 * @api public
 */

Emitter.prototype.hasListeners = function(event){
  return !! this.listeners(event).length;
};

Component: component/emitter
Bower or standalone: Wolfy87/EventEmitter
Node.js EventEmitter
理解Event Emitter
深入浅出Node.js(四):Node.js的事件机制