如何构建自定义 Node.js 事件发射器

简介: 如何构建自定义 Node.js 事件发射器

2.自定义事件
自定义事件发生在 Node.js 的 JavaScript 核心内。 这些事件由名为的 Node.js 类处理 EventEmitter.

EventEmitter是 Node.js 中的一个 JavaScript 类,用于处理自定义事件,因为 JavaScript 没有任何内置功能来处理事件。

通常,当 libuv 中发生事件时,libuv 会生成自定义 JavaScript 事件,以便轻松处理它们。 因此,即使 Node.js 事件实际上是两种不同类型的事件,它们也可能被视为单个实体。

在本文中,我们的重点将放在自定义 JavaScript 事件和事件发射器上。

超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →

什么是事件发射器?
Node.js 使用如上所述的事件驱动编程模式。 这种设计模式用于生产和消费事件,主要用于前端(浏览器)。 诸如按钮单击或按键之类的用户操作会生成一个事件。

这些事件具有关联的函数,称为侦听器,当它们发出时,它们被调用以处理它们的相应事件。

事件驱动模式有两个主要组成部分:

事件处理程序(侦听器)。 这是发出事件时将调用的函数。 可以有多个侦听器在侦听一个事件。 当事件发出时,这些监听器将被同步调用。

侦听事件并调用相关侦听器来处理该事件的主循环。

Node.js 通过 EventEmitter班级。 这 EventEmitter类是 events核心 Node.js 模块。 它为我们提供了一种发出和处理事件的方式,并且它暴露了——除此之外—— on和 emit方法。

在本文中,我们将使用支持 Node.js 事件发射器的核心原理构建自定义事件发射器,以便我们更好地了解它们的工作原理。

下面的代码展示了如何使用 EventEmitter目的。

const EventEmitter = require('events');
const eventEmitter = new EventEmitter ();

eventEmitter.on('greet', () => {
console.log('Hello world!');
});

eventEmitter.emit('greet');
在上面的代码中, eventEmitter.on方法用于注册处理事件的侦听器,而 eventEmitter.emit方法用于发出事件。

通过发出 greet上面的事件,监听的函数 greet事件被调用,并且 Hello world!被记录到控制台。

公开的其他方法 EventEmitter对象是:

eventEmitter.once(): 这增加了一个一次性监听器

eventEmitter.off(): 这是一个别名 eventEmitter.removeListener(). 它从事件中删除事件侦听器

eventEmitter.listnersCount():这将返回侦听事件的侦听器数量

在 Node.js 中,还有其他可以发出事件的对象。 但是,所有发出事件的对象都是 EventEmitter班级。 为了更好地理解事件发射器,让我们自己构建。

来自 LogRocket 的更多精彩文章:
不要错过 The Replay 来自 LogRocket 的精选时事通讯

了解 LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题

使用 React 的 useEffect 优化应用程序的性能

之间切换 在多个 Node 版本

了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画

探索 Tauri ,一个用于构建二进制文件的新框架

比较 NestJS 与 Express.js

为什么使用事件发射器?
Node.js 通过 EventEmitter班级。 这 EventEmitter类是 events核心 Node.js 模块。

事件发射器和监听器对于 Node.js 开发至关重要。 它们使 Node.js 运行时能够完成其单线程、异步、非阻塞 I/O 功能,这是 Node.js 出色性能的关键。

内的班级成员 EventEmitter
Node.js EventEmitter类为我们提供了一种发出和处理事件的方法。 在其中,它公开了许多 类成员 :

这 emit方法顺序和同步地调用每个监听触发事件的监听器——将提供的参数传递给每个监听器

这 on方法有两个参数:事件名称和事件监听器。 它将此事件侦听器函数添加到侦听器数组的末尾

off是的别名 emitter.removeListener()

这 removeListener方法有两个参数:事件名称和事件监听器。 然后在指定事件触发时从事件数组中删除此事件侦听器

addListener是的别名 on方法

自定义事件发射器的一般模式
事件发射器的一般思想是拥有一个事件对象,其键充当自定义事件,相应的值将是在事件发出时同步调用的侦听器数组。

考虑下面的代码:

const GreetHandlers = [
()=> {console.log("Hello world!"),
()=> {console.log("Hello Developer!"),
()=> {console.log("Hello From LogRocket!"}
];

const events = {
"greet": GreetHandlers
}
在这里, events对象有一个属性: "greet". 此对象的每个属性名称都被视为一个唯一事件,这意味着 "greet"财产是一个事件。

的价值 "greet"属性(事件)是 GreetHandlers大批。 这是一个包含函数(或侦听器)的数组,当 "greet"事件发生。

为了同步调用这些函数,我们遍历数组并调用每个函数,如下所示:

GreetHandlers.forEach(listener => {
listener();
});

// Output:
// "Hello world!"
// "Hello Developer!"
// "Hello From LogRocket!"
上面的示例简要概述了 Node.js 事件发射器中使用的模式。 我们将使用与在下一节中构建自己的事件发射器相同的模式。

在 Node.js 中构建自定义事件发射器
虽然 Node.js EventEmitter是一个 JavaScript 类,我们将使用函数构造函数构建我们自己的类,以便我们了解后台发生的事情。

JavaScript 中的类为我们提供了一种新的、简单的语法来处理 JavaScript 的 原型继承 。 因为 JavaScript 中的类是原型模式的语法糖,所以很多事情都发生在我们隐藏的引擎盖下。

要构建我们的自定义事件发射器,请按照以下步骤操作:

1.创建事件发射器函数构造函数
这应该有一个属性(事件对象)。

function Emitter( ) {
this.events = { };
}
这 events上面的对象将作为保存所有自定义事件的主要对象。 每个 key和 value这个对象对应于一个事件和它的监听器数组。

function Emitter( ) {
this.events = {
"greet": [
()=> {},
()=> {},
()=> {},
],
"speak": [
()=> {},
()=> {},
()=> {},
]
}
2.给事件发射器原型添加方法
面向对象的 JavaScript 为我们提供了一种在应用程序中共享属性和方法的简洁方式。 这是因为原型模式允许对象访问原型链下游的属性,这意味着对象可以访问其原型、其原型的原型以及其他地方的属性。

如果对象中不存在该方法或属性,则 JavaScript 引擎首先在对象的原型中搜索该方法或属性。 如果它在该对象的原型中没有找到它,它会继续沿着原型链向下搜索。 这种继承模式被称为原型继承。

由于 JavaScript 的原型继承,当我们向对象的原型添加属性和方法时,该对象的所有实例都可以访问它们。

请参见下面的代码中的此处,我们在其中添加 on方法:

Emitter.prototype.on = function (type, listener) {
// check if the listener is a function and throw error if it is not
if(typeof listener !== "function") {
throw new Error("Listener must be a function!")
}
// create the event listener property (array) if it does not exist.
this.events[type] = this.events[type] || [];
// adds listners to the events array.
this.events[type].push(listener);
}
这增加了 on函数原型 Emitter对象,它允许所有实例 Emitter对象继承此方法。 这 on方法有两个参数,即 type和 listener(一个函数)。

首先, on方法检查是否 listener是一个函数。 如果不是,则会引发错误,如下所示:

if(typeof listener !== "function") {
throw new Error("Listener must be a function!")
}
此外,该 on方法检查是否 type的事件存在于 events对象(作为键)。 如果它不存在,它会添加一个事件(作为键)到 events对象并将其值设置为空数组。 最后,它将侦听器添加到相应的事件数组中: this.events[type].push(listener);.

现在让我们添加 emit方法:

Emitter.prototype.emit = function(type) {
if (this.events[type]) { // checks if event is a property on Emitter
this.events[type].forEach(function(listener) {
// loop through that events array and invoke all the listeners inside it.
listener( );
})
}
}

// if used as a node module. Exports this function constructor
modules.exports = Emitter;
// This makes it available from the require()
// so we can make as many instances of it as we want.
上面的代码添加了 emit的方法 Emitters原型。 它只是检查事件类型是否存在(作为键) events目的。 如果它存在,那么它会调用上面已经讨论过的所有相应的侦听器。

this.events[type]返回对应事件属性的值,该属性是一个包含监听器的数组。

因此,下面的代码循环遍历数组并同步调用其所有侦听器。

this.events[type].forEach(function(listener) {
// loop through that events array and invoke all the listeners inside it.
listener( );
})
要使用我们的事件发射器,我们必须手动发射一个事件。

// if used in a Node.js environment require the module as seen below.
const Emitter = require('./emitter');

const eventEmitter = new Emitter();

eventEmitter.on('greet', ()=> {
console.log("Hello World!");
});

eventEmitter.on('greet', ()=> {
console.log("Hello from LogRocket!");
});

eventEmitter.emit("greet"); // manually emit an event
在上面的代码中,我们首先需要并创建一个实例 Emitter使用这个的模块:

const Emitter = require('./emitter');

const eventEmitter = new Emitter();
然后我们将监听器分配给 "greet"事件使用 on方法。

eventEmitter.on('greet', ()=> {
console.log("Hello World!");
});

eventEmitter.on('greet', ()=> {
console.log("Hello from LogRocket!");
});
最后,我们手动发出 greet使用这一行的事件:

emtr.emit("greet");
Google翻译恢复访问软件,修复谷歌翻译服务,懒人一键操作即可搞定!
上图显示了运行我们的代码的结果。 在此处查看沙盒中的完整代码 。
添加更多事件方法
这 addListener方法
值得注意的是, on方法实际上是 addListener事件发射器中的方法。 因此,我们需要重构实现。

Emitter.prototype.addListener = function (type, listener) {
// check if the listener is a function and throw error if it is not
if (typeof listener !== "function") {
throw new Error("Listener must be a function!");
}
// create the event listener property (array) if it does not exist.
this.events[type] = this.events[type] || [];
// adds listners to the events array.
this.events[type].push(listener);
};
Emitter.prototype.on = function (type, listener) {
return this.addListener(type, listener);
};
上面的代码仍然有效,但在这个版本中, addListener和 on方法做同样的事情。

这 listenersCount方法
还有 listenersCount方法。 这将返回正在侦听特定事件的函数(侦听器)的总数。 我们将在下面实现:

Emitter.prototype.listenerCount = function (type) {
let listnersCount = 0;
let listeners = this.events[type] || [];
listnersCount = listners.length;
console.log("listeners listnersCount", listnersCount);
return listnersCount;
};
在这里,我们告诉简单存储指定事件的侦听器数组到 listeners变量使用:

let listeners = this.events[type] || [];
如果未找到该事件,则存储一个空数组。 然后,我们返回 length的 listener variable.

Node.js 中的事件发射器遵循同样的想法,但它们有很多额外的功能。 我们只是构建了一个简单的版本。 您可以 在此处使用纯 JavaScript 编写最终代码 。

结论
事件发射器是 Node.js JavaScript 核心许多部分的基本构建块。 所有发出事件的 Node.js 对象,例如流和 HTTP 模块,都是 EventEmitter班级。 它是 Node.js 中的一个重要对象,由 events模块。

通过 EventEmitter类,Node.js 将事件驱动编程带到了服务器端。 我希望通过构建我们设计的事件发射器,您能够了解更多关于 Node.js EventEmitter班级。

仅200个 监控生产中失败和缓慢的网络请求
部署基于节点的 Web 应用程序或网站是很容易的部分。 确保您的 Node 实例继续为您的应用程序提供资源是事情变得更加困难的地方。 如果您有兴趣确保对后端或第三方服务的请求成功, 请尝试 LogRocket 。

LogRocket 就像一个用于网络和移动应用程序的 DVR,记录用户与您的应用程序交互时发生的所有事情。 无需猜测问题发生的原因,您可以汇总和报告有问题的网络请求,以快速了解根本原因。

LogRocket 检测您的应用程序以记录基准性能时间,例如页面加载时间、第一个字节的时间、缓慢的网络请求,并记录 Redux、NgRx 和 Vuex 操作/状态。

相关文章
|
4月前
|
JavaScript 前端开发 物联网
JavaScript:构建动态世界的引擎
JavaScript:构建动态世界的引擎
|
4月前
|
前端开发 JavaScript 开发者
JavaScript:构建动态网络的引擎
JavaScript:构建动态网络的引擎
|
4月前
|
前端开发 JavaScript 开发者
JavaScript:构建动态Web的核心力量
JavaScript:构建动态Web的核心力量
|
8月前
|
前端开发 算法 API
构建高性能图像处理Web应用:Next.js与TailwindCSS实践
本文分享了构建在线图像黑白转换工具的技术实践,涵盖技术栈选择、架构设计与性能优化。项目采用Next.js提供优秀的SSR性能和SEO支持,TailwindCSS加速UI开发,WebAssembly实现高性能图像处理算法。通过渐进式处理、WebWorker隔离及内存管理等策略,解决大图像处理性能瓶颈,并确保跨浏览器兼容性和移动设备优化。实际应用案例展示了其即时处理、高质量输出和客户端隐私保护等特点。未来计划引入WebGPU加速、AI增强等功能,进一步提升用户体验。此技术栈为Web图像处理应用提供了高效可行的解决方案。
|
9月前
|
前端开发 搜索推荐 JavaScript
如何通过DIY.JS快速构建出一个DIY手机壳、T恤的应用?
DIY.JS 是一款基于原生 Canvas 的业务级图形库,专注于商品定制的图形交互功能,帮助开发者轻松实现个性化设计。适用于 T 恤、手机壳等多种商品场景。它自带丰富功能,无需从零构建,快速集成到项目中。通过创建舞台、添加模型、定义 DIY 区域和添加素材四个步骤即可完成基础用法。支持在线演示体验,文档详细,易上手。
401 57
|
9月前
|
JavaScript 前端开发 Java
【Java进阶】详解JavaScript事件
总的来说,JavaScript事件是JavaScript交互设计的核心,理解和掌握JavaScript事件对于编写高效、响应式的网页应用至关重要。
183 15
|
9月前
|
前端开发 JavaScript NoSQL
使用 Node.js、Express 和 React 构建强大的 API
本文详细介绍如何使用 Node.js、Express 和 React 构建强大且动态的 API。从开发环境搭建到集成 React 前端,再到利用 APIPost 高效测试 API,适合各水平开发者。内容涵盖 Node.js 运行时、Express 框架与 React 库的基础知识及协同工作方式,还涉及数据库连接和前后端数据交互。通过实际代码示例,助你快速上手并优化应用性能。
|
10月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
10月前
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一