详解如何模拟实现node中的Events模块(通俗易懂版)

2020-06-17 05:47:48易采站长站整理

Nodejs 的大部分核心 API 都是基于异步事件驱动设计的,事件驱动核心是通过 node 中 Events 对象来实现事件的发送和监听回调绑定,我们常用的 stream 模块也是依赖于 Events 模块是来实现数据流之间的回调通知,如在数据到来时触发 data 事件,流对象为可读状态触发 readable 事件,当数据读写完毕后发送 end 事件。

既然 Events 模块如此重要,我们有必要来学习一下 Events 模块的基本使用,以及如何模拟实现 Events 模块中常用的 api

一、Events 模块的基本使用以及简单实现

首先我们了解一下 Events 模块的基本用法,其实 Events 模块本质上是观察者模式的实现,所谓观察者模式就是:

它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知

观察者模式有对应的观察者以及被观察的对象,在 Events 模块中,对应的实现就是 on 和 emit 函数


const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('嗨', (str) => {
console.log(str);
});
myEmitter.emit('嗨','你好');

从上述的使用中,我们可以知道 on 是用来监听事件的发生,而 emit 是用来触发事件的发生,一旦 emit 触发了事件,on 就会被通知到,从而执行对应的回调函数。

有了这个实例,我们可以思考下如何实现这个 EventEmitter 类。

思路:当我们执行 on 函数时,我们可以将回调函数保存起来,等到 emit 触发了事件时,将回调函数拿出来执行,那么就可以实现了事件的监听以及订阅了。


class EventEmitter{
constructor(){
#事件监听函数保存的地方
this.events={};
}
on(eventName,listener){
if (this.events[eventName]) {
this.events[eventName].push(listener);
} else {
#如果没有保存过,将回调函数保存为数组
this.events[eventName] = [listener];
}
}
emit(eventName){
#emit触发事件,把回调函数拉出来执行
this.events[eventName] && this.events[eventName].forEach(listener => listener())
}
}

上述就实现了一个简单的 EventEmitter 类,下面来实例一下:


let event = new EventEmitter();
event.on('嗨',function(){
console.log('你好');
});
event.emit('嗨');
#输出:你好

完善:我们注意到在原生的 EventEmitter 类中,emit 是可以传递参数到我们的回调函数中,那么我们实现的类也应该支持传递参数。我们对 emit 进行如下更改