深入理解node核心模块 -- EventEmitter及实现原理

1. Events模块简介

  • node的特性:单线程 异步 非阻塞I/O 基于事件驱动的运行在服务器端轻量、高效的脚本语言;

  • Events模块是nodejs的核心模块,是node实现事件驱动的基础,node中几乎所有的模块(如http, fs等)都继承该模块;

  • Events模块实现了事件注册,通知等功能,是观察者模式(事件发布/订阅模式)的实现;

  • 只要继承EventEmitter类,就可拥有事件注册、触发事件等,所有能触发事件的对象都是EventEmitter类的实例, 例如:

    • net.Server 对象会在每次有新连接时触发事件;
    • fs.ReadStream 会在文件被打开时触发事件;
    • 流对象 会在数据可读时触发事件;
  • 创建一个新类, 使支持 EventEmitter 事件

eg1: 借助util模块
    
    let EventEmitter = require('events');
    let util = require('util');
    function  WriteStream () {
        EventEmitter.call(this);  //继承私有属性
    }
    util.inherits(WriteStream, EventEmitter);  //原型继承,继承公有
    /** 
     * 定义一个WriteStream类,把EventEmitter类的方法添加到新创建的WriteStream 类中,使WriteStream的实例具有EventEmitter的方法。
     * 相当于:
     * Object.setPrototypeOf(ctor.prototype, superCtor.prototype);  //指定的对象的原型 
     * ctor.prototype.__proto__ = superCtor.prototype;
     */
    
eg2: 借助es6 extends方法
    const EventEmitter = require('events');
    class MyEmitter extends EventEmitter {}
    const myEmitter = new MyEmitter();
   
    myEmitter.on('event', () {
        console.log('触发了一个事件了');
    });
    myEmitter.emit('event');  //触发事件

    当我们订阅了'event'事件后,可以在任何地方通过emit('event')来执行事件回调;
复制代码

2. 相关API

1. 导入模块(创建emitter实例)
    var EE = require('events');   //events模块只提供了一个EventEmitter类,所以返回的就是EventEmitter

2. 注册绑定事件
    EE.addListener(event, listener);
    EE.on(event, listener);   //相当于增加观察者,addListener和on这两个方式作用是一样的
    
    EE.once(event, listener);  //绑定的事件监听器只会执行一次,然后就会被删除掉
    
    //添加了任意的监听函数时会触发newListener
    EE.on('newListener', (type, listener) => {
    });
    EE.on('removeListener');
    
3. 触发事件
    EE.emit(event); 

4. 移除事件
    EE.removeListener(event, listener);
    EE.removeAllListeners([event]);  //移除所有
    
5. 其它api
    EE.setMaxListeners(n);  //设置同一事件的监听器最大绑定数,默认情况下,超过10个就会警告;设置为0,是无限制;
    EE.listenerCount()  //查看事件监听器数量
    
    

复制代码

3. 简单实现一个自己的myEventEmitter库

首先实现这个myEventEmitter库,需要先对观察者模式进行了解,这样写起来才会得心应手;

观察者模式管理消息分发的一种方式,这种模式中 ,发布消息的一方不需要知道这个消息会给谁,而订阅一方也无需知道消息的来源。

简单原理描述:this.events维护一个信号对应函数的列表,通过这个索引,可以对这个信号进行增、删等操作,你只需要按照这个信号执行对象的回调函数;

class MyEvents {
	constructor () {
		this.events = {} //存储事件监听函数
		this.maxListeners = 10 //一种函数类型,最大监听函数数量
	}
	
	setMaxListeners (maxNum) {
		this.maxListeners = maxNum
	}
	
	getMaxListeners () {
		return this.maxListeners
	}
	
	listeners (event) {
		return this.events[event]
	}
	
	addListener (type, listener) {
		if (this.events[type]) {
			if (this.maxListeners != 0 && this.events[type].length > this.maxListeners) {
				return console.error(`该${type}事件类型的listteners超出限制,使用emitter.setMaxListeners() 来增加添加事件监听数量。`)
			}
			this.events[type].push(listener)
		} else {
			this.events[type] = [listener]
		}
	}
	
	once (type, listener) {
		//执行后立即销毁
		let wrapper = (...rest) => {
			listener.apply(this, rest)
			this.removeListener(type, wrapper)
		}
		this.addListener(type, wrapper)
	}
	
	removeListener (type, listener) {
		if (this.events[type]) {
			this.events[type] = this.events[type].filter(ev => {
				ev != listener
			})
			//抛弃掉等于listener的
		}
	}
	
	removeAllListener (type) {
		delete this.events[type]
	}
	
	emit (type, ...rest) {
		this.events[type] && this.events[type].forEach(listener => {
			listener.apply(this, rest)
		})
	}
}

MyEvents.prototype.on = MyEvents.prototype.addListener
module.exports =  MyEvents复制代码
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值