nodejs的大多数核心API都是基于异步事件驱动设计的。事件驱动的核心是通过Node中的Events对象发送事件并监控回调绑定。我们常用的流模块也是依靠Events模块实现数据流之间的回调通知,比如数据到达时触发data事件,流对象可读时触发可读事件,数据读写时发送end事件。
由于事件模块非常重要,我们有必要了解事件模块的基本用法,以及如何模拟和实现事件模块中常用的API
首先,事件模块的基本用途和简单实现
首先,让我们看看事件模块的基本用法。事实上,事件模块本质上是观察者模式的实现,即:
它定义了对象之间的一对多关系,允许多个观察者对象同时聆听某个主体对象。当一个对象改变时,所有依赖它的对象都会被通知
观察者模式有对应的观察者和被观察对象。在事件模块中,相应的实现是on和emit函数
const event emitter=require(' events ');class MyEmitter扩展了event emitter { } const MyEmitter=new MyEmitter();MyEmitter.on ('hi ',(str)={ console . log(str);});my mitter . emit(' hi ',' hello ');从上面的使用中,我们可以知道on用于监控事件的发生,而emit用于触发事件的发生。一旦emit触发一个事件,on将被通知,相应的回调函数将被执行。
通过这个例子,我们可以考虑如何实现这个事件发射器类。
思考:当我们执行on函数的时候,可以保存回调函数,当emit触发事件的时候,可以把回调函数取出来执行,然后就可以监控和订阅事件了。
类eventemitter {constructor () {#其中保存了事件侦听器函数this . events={ };} on(eventName,侦听器){ if(this . events[event name]){ this . events[event name]。push(监听器);} else {#如果没有保存,将回调函数保存为数组this。事件[事件名称]=[侦听器];}} emit(eventName){ #emit触发一个事件,并拉出回调函数来执行此操作。events [eventname]这。事件[eventname]。foreach (listener=listener ())}}上面实现了一个简单的EventEmitter类。让我们举个例子:
let event=new event emitter();Event.on ('hi ',function(){ console . log(' hello ');});event . emit(' hi ');# output:多么完美:我们注意到emit可以在原生的EventEmitter类中将参数传递给我们的回调函数,所以我们实现的类也应该支持传递参数。我们对发射进行了以下更改
发出(事件名称,rest){ #emit触发一个事件,并拉出回调函数来执行此操作。事件[事件名称]这。事件[事件名称]。foreach(侦听器=侦听器。apply (this,rest))}被完善并再次实例化,如下所示:
let event=new event emitter();Event.on ('hi ',function(str){ console . log(str);});Event.emit ('hi ',' hello ');#输出:你好2。事件模块中常用的api
除了on和emit函数,Events模块还包含许多常用的API。让我们逐一介绍几个实用的API
API name API方法描述了在(事件名称,侦听器)别名上添加侦听器(事件名称,侦听器),并在侦听器数组尾部添加一个侦听器以移除侦听器(事件名称,侦听器)从名为eventName的事件的侦听器数组中移除指定的侦听器移除所有侦听器(事件名称,侦听器)移除所有侦听器或指定事件名称事件的侦听器一次(事件名称,侦听器)向名为event name(事件名称)的事件侦听器添加单个侦听器返回名为event name的事件的侦听器数组副本。setMaxListeners(n)可以修改指定事件发射器实例的侦听器数量限制。1.addListener和on方法的使用和实现。
在事件模块中,addListener和on方法的使用方式相同,但名称不同。我们可以通过原型建立两种功能之间的平等关系
事件发射器。原型。addlistener=eventemitter。原型。2号。removelistener以及off方法使用和实现
removeListener方法可以从具有指定名称的侦听器数组中移除指定的侦听器,以便在再次发生发出事件时,不会触发on绑定的回调函数,如下所示:
const event emitter=require(' events ');class MyEmitter扩展了event emitter { } const MyEmitter=new MyEmitter();let回调=(str)={ console . log(str);}myEmitter.on ('hi ',callback);my mitter . emit(' hi ',' hello ');#输出:hello myemitter . removelistener(' hi ',回调);my mitter . emit(' hi ',' hello ');#无输出实现思路:我们只需要在执行removeListener函数时删除之前保存的回调函数
remove侦听器(事件名称,侦听器){#确保回调函数数组存在,并为此移除指定的侦听器。事件[事件名称]这。事件[事件名称]=this。事件[事件名称]。过滤器(l=l!=监听器);}同时,removeListener和off方法具有相同的函数,但名称不同,因此可以通过以下方法赋值:
event emitter . prototype . remove listener=event emitter . prototype . off 3 . removealllisteners方法的使用和实现
移除所有侦听器移除所有侦听器或指定事件名称事件的侦听器。事实上,removeall listener包含removeListener的功能,只是removeListener只能指定特定的侦听器,而removeall listener可以移除所有侦听器。
实现思路:执行removeAllListeners后,可以删除所有回调函数
删除所有侦听器(事件名称){#删除所有侦听器删除此。事件[事件名称]} 4。一次性方法的使用和实现
once方法的描述是向名为eventName的事件添加一个侦听器。实际上,通过一次添加的监听器只能执行一次,执行一次后就会被销毁,不能再次执行
const event emitter=require(' events ');class MyEmitter扩展了event emitter { } const MyEmitter=new MyEmitter();MyEmitter.once ('hi ',(str)={ console . log(str);});my mitter . emit(' hi ',' hello ');my mitter . emit(' hi ',' hello ');my mitter . emit(' hi ',' hello ');#你只能输出如何实现一次发出的思路:执行一次监控的事件回调函数后,通过removeListener将事件监听器解绑,这样当事件再次发出时,回调就不会再次执行,从而保证事件回调只能执行一次。
一次(eventName,listener) {#再次更改监听回调函数,以便执行后可以销毁。让听众=(.rest)={listener。应用(这个,休息);#解开这个。执行后移除listener(类型,包装);} this.on(eventName,Relistener);} 5.侦听器方法的使用和实现
listeners方法返回名为eventName的事件的侦听器数组的副本,实际上是为了获取eventName中的所有回调函数。这个很容易实现,就不赘述了。代码如下:
侦听器(event name){返回此。事件[eventname]} 6。setmaxlisteners方法的使用和实现
默认情况下,如果为特定事件添加了10个以上的侦听器,事件发射器会打印一条警告。这有助于发现内存泄漏,但不是所有事件都应该限制在10个侦听器。方法可以修改指定事件发射器实例的限制。将该值设置为无穷大(或0)意味着监听程序的数量没有限制。
const event emitter=require(' events ');class MyEmitter扩展了event emitter { } const MyEmitter=new MyEmitter();let回调=(str)={ console . log(str);}for(让I=0;i=11I) {myEmitter.on ('hi ',callback);} MyMitter . emit(' hi ',' hello ');输入结果如下:
实施思路:
让我们将特定事件的最大侦听器设置为常量10
Constructor(){ #其中保存了事件侦听函数this . events={ };#这是最大数量的侦听器。_ maxListeners=10}然后,在我们的on功能中,判断这个监听者的号码并进行提示
on(eventName,侦听器){ if(this . events[event name]){ this . events[event name]。push(监听器);#如果超过最大限制且不为0,则在(这。_maxListeners!=0这个。事件[类型]。长度=这个。_ max listeners){控制台。错误('超过侦听器的最大数量可能会导致内存泄漏');}} else {#如果没有保存,将回调函数保存为数组this。events[event name]=[listener];}}我们还支持根据用户输入改变_maxListeners变量,也就是我们的setMaxListeners()函数
setmaxlisteners(max listeners){ this。_ maxlisteners=maxlisteners} iii。摘要
本文从节点的Events模块入手,然后介绍Events模块常用的API的使用,从这些API中简单地一步步考虑使用这些API的内在原理,并简单地实现这些API。希望大家看完文章后能对Events模块有进一步的了解。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。