Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EventEmitter 理解 #16

Open
pfan123 opened this issue Aug 1, 2017 · 0 comments
Open

EventEmitter 理解 #16

pfan123 opened this issue Aug 1, 2017 · 0 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented Aug 1, 2017

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的事件机制

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant