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

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 进行如下更改

emit(eventName,...rest){ #emit触发事件,把回调函数拉出来执行 this.events[eventName] && this.events[eventName].forEach(listener => listener.apply(this,rest)) }

完善之后,重新实例化,如下:

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

二、Events 模块中常用的 api

Events 模块中除了 on、emit 函数之外,还包含了很多常用的 api,我们一一来介绍几个实用的 api

API名称 API方法描述
addListener(eventName, listener)   on(eventName, listener)别名,为指定事件添加一个监听器到监听器数组的尾部  
removeListener(eventName, listener)   从名为 eventName 的事件的监听器数组中移除指定的 listener  
removeAllListeners(eventName, listener)   移除全部监听器或指定的 eventName 事件的监听器  
once(eventName, listener)   添加单次监听器 listener 到名为 eventName 的事件  
listeners(eventName)   返回名为 eventName 的事件的监听器数组的副本  
setMaxListeners(n)   可以为指定的 EventEmitter 实例修改监听器数量限制  

1. addListener 与 on 方法使用与实现

在 Events 模块中,addListener 与 on 方法的使用是完成相同的,只是名字不同,我们可以通过原型来给两个函数建立相等关联

EventEmitter.prototype.addListener=EventEmitter.prototype.on

2. removeListener 与 off 方法使用与实现

removeListener 方法可以从指定名字的监听器数组中移除指定的 listener,这样的话,当再次 emit 事件的时候,不会触发 on 绑定的回调函数,如下:

const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); let callback = (str) => { console.log(str); } myEmitter.on('嗨', callback); myEmitter.emit('嗨','你好');#输出:你好 myEmitter.removeListener('嗨',callback); myEmitter.emit('嗨','你好');#无输出

实现思路:我们只要在执行 removeListener 函数的时候,将先前保存的回调函数去除掉即可

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/2f837dba801c51cfe7e21d7be6f90fed.html