Node.js 中的 Event 模块详解
Node.js 中的 Event 模块是实现事件驱动编程的核心模块。它基于观察者模式,允许对象(称为“事件发射器”)发布事件,而其他对象(称为“事件监听器”)可以订阅并响应这些事件。这种模式非常适合处理异步操作和事件驱动的场景。
1. 概念
1.1 事件驱动编程
事件驱动编程是一种编程范式,程序的执行流程由事件(如用户输入、文件读取完成、网络请求响应等)决定。Node.js 的核心设计理念就是基于事件驱动的非阻塞 I/O 模型。
1.2 事件发射器(EventEmitter)
EventEmitter 是 Node.js 中实现事件驱动编程的核心类。它提供了以下功能:
- 发布事件:通过
emit()方法触发事件。 - 订阅事件:通过
on()或addListener()方法监听事件。 - 取消订阅:通过
removeListener()或off()方法移除事件监听器。
2. 定义与用法
2.1 引入 EventEmitter
EventEmitter 是 events 模块的一个类,使用前需要引入:
const EventEmitter = require('events');
2.2 创建事件发射器
可以通过继承 EventEmitter 或直接实例化来创建事件发射器。
方法 1:直接实例化
const EventEmitter = require('events');// 创建事件发射器实例
const myEmitter = new EventEmitter();// 监听事件
myEmitter.on('greet', (name) => {console.log(`Hello, ${name}!`);
});// 触发事件
myEmitter.emit('greet', 'Alice'); // 输出:Hello, Alice!
方法 2:继承 EventEmitter
const EventEmitter = require('events');// 自定义类继承 EventEmitter
class MyEmitter extends EventEmitter {}// 创建自定义类的实例
const myEmitter = new MyEmitter();// 监听事件
myEmitter.on('greet', (name) => {console.log(`Hello, ${name}!`);
});// 触发事件
myEmitter.emit('greet', 'Bob'); // 输出:Hello, Bob!
2.3 常用方法
1. on(eventName, listener)
- 监听指定事件。
eventName:事件名称。listener:事件触发时的回调函数。
myEmitter.on('data', (data) => {console.log('Data received:', data);
});
2. emit(eventName[, ...args])
- 触发指定事件。
eventName:事件名称。args:传递给监听器的参数。
myEmitter.emit('data', { message: 'Hello, world!' });
3. once(eventName, listener)
- 监听事件,但只触发一次。
- 触发后自动移除监听器。
myEmitter.once('init', () => {console.log('Initialized!');
});myEmitter.emit('init'); // 输出:Initialized!
myEmitter.emit('init'); // 无输出
4. removeListener(eventName, listener)
- 移除指定事件的监听器。
const listener = (data) => {console.log('Data received:', data);
};myEmitter.on('data', listener);
myEmitter.removeListener('data', listener);
5. off(eventName, listener)
removeListener的别名,功能相同。
6. removeAllListeners([eventName])
- 移除所有监听器,或指定事件的所有监听器。
myEmitter.removeAllListeners('data');
7. listenerCount(eventName)
- 返回指定事件的监听器数量。
const count = myEmitter.listenerCount('data');
console.log('Listener count:', count);
3. 优缺点
3.1 优点
- 解耦:
- 事件驱动模式将事件的发布和订阅解耦,使代码更模块化和可维护。
- 异步支持:
- 非常适合处理异步操作,如文件 I/O、网络请求等。
- 灵活性:
- 可以动态添加或移除事件监听器,适应不同的业务需求。
- 内置支持:
- Node.js 的许多核心模块(如
fs、net、http)都基于EventEmitter。
- Node.js 的许多核心模块(如
3.2 缺点
- 回调地狱:
- 如果事件嵌套过多,可能会导致回调地狱,降低代码可读性。
- 错误处理:
- 如果没有正确监听
error事件,可能会导致程序崩溃。
- 如果没有正确监听
- 内存泄漏:
- 如果未及时移除监听器,可能会导致内存泄漏。
- 调试困难:
- 事件驱动的代码流程不如同步代码直观,调试起来可能更复杂。
4. 最佳实践
4.1 错误处理
始终监听 error 事件,避免未捕获的错误导致程序崩溃。
myEmitter.on('error', (err) => {console.error('Error occurred:', err.message);
});myEmitter.emit('error', new Error('Something went wrong!'));
4.2 避免内存泄漏
及时移除不再需要的监听器。
const listener = () => {console.log('Event triggered');
};myEmitter.on('event', listener);// 移除监听器
myEmitter.off('event', listener);
4.3 使用 once 替代 on
如果事件只需要触发一次,使用 once 而不是 on,避免手动移除监听器。
myEmitter.once('init', () => {console.log('Initialized!');
});
5. 示例:文件读取事件
以下是一个结合 fs 模块的文件读取示例:
const fs = require('fs');
const EventEmitter = require('events');class FileReader extends EventEmitter {readFile(filePath) {fs.readFile(filePath, 'utf8', (err, data) => {if (err) {this.emit('error', err);} else {this.emit('data', data);}});}
}const reader = new FileReader();reader.on('data', (data) => {console.log('File content:', data);
});reader.on('error', (err) => {console.error('Failed to read file:', err.message);
});reader.readFile('example.txt');
6. 总结
EventEmitter是 Node.js 中实现事件驱动编程的核心工具。- 优点:解耦、异步支持、灵活性高。
- 缺点:回调地狱、错误处理复杂、可能内存泄漏。
- 适用场景:异步操作、事件驱动的应用(如服务器、文件 I/O 等)。
通过合理使用 EventEmitter,可以编写出高效、模块化的 Node.js 应用程序。
相关文章:
Node.js 中的 Event 模块详解
Node.js 中的 Event 模块是实现事件驱动编程的核心模块。它基于观察者模式,允许对象(称为“事件发射器”)发布事件,而其他对象(称为“事件监听器”)可以订阅并响应这些事件。这种模式非常适合处理异步操作和…...
C# 添加图标
一、前言 为应用程序添加图标是优化用户界面、提升应用辨识度的重要操作。合适的图标能帮助用户快速识别和区分不同应用,增强应用的易用性和专业性。 本指南旨在为你提供详细、易懂的步骤,教你如何为应用程序的窗体添加图标。从图标素材的获取到具体的…...
Docker 入门与实战:从安装到容器管理的完整指南
🚀 Docker 入门与实战:从安装到容器管理的完整指南 🌟 📖 简介 在现代软件开发中,容器化技术已经成为不可或缺的一部分。而 Docker 作为容器化领域的领头羊,以其轻量级、高效和跨平台的特性,深…...
4.【线性代数】——矩阵的LU分解
四 矩阵的LU分解 1. AB的逆矩阵2. 转置矩阵3. ALU3.1 2x2矩阵3.2 3x3矩阵3.3 nxn的矩阵分解的次数? 1. AB的逆矩阵 { ( A B ) ( B − 1 A − 1 ) I ( B − 1 A − 1 ) ( A B ) I ⇒ ( A B ) − 1 B − 1 A − 1 \begin{cases} (AB)(B^{-1}A^{-1}) I\\ (B^{-1}A^…...
ELK8.17部署(Ubantu24x64)
检查java环境 ELK8.x不支持java8 若无环境可执行 sudo apt install openjdk-17-jre-headless 准备安装包 官网下载地址: ELK products 搜Elasticsearch、Kibana、Logstash、Filebeat versions需一致,这里使用8.17.0 Elasticsearch Kibana Logstash Filebeat e…...
什么是算法的空间复杂度和时间复杂度,分别怎么衡量。
1. 时间复杂度 时间复杂度衡量的是算法运行时间与输入规模之间的关系。它通常用大O记号(Big O Notation)表示,例如 O(1)、O(n)、O(n2) 等。 衡量方法: 常数时间复杂度 O(1):无论输入规模如何,算法的执行时…...
HCIA项目实践---ACL访问控制列表相关知识和配置过程
十 ACL访问控制列表 1 策略的概念 在网络连通之后, 把所有为了追求控制而实现的技术都叫策略 2 访问控制 在路由器流量流入或者流出的接口上,匹配流量,执行相应的动作。(流量流入或者流出的接口并不是一个固定的概念而是一个相对的…...
细说STM32F407单片机RTC入侵检测和时间戳的原理及使用方法
目录 一、入侵检测的功能 二、示例功能 三、项目设置 1、晶振、DEBUG、CodeGenerator、USART6、KEYLED 2、RTC (1)设置RTC的模式。 (2)General、Time、Date\Wake Up分组 (3)Tamper分组 1ÿ…...
STM32 CAN过滤器配置和应用方法介绍
目录 概述 一、CAN过滤器核心概念 二、过滤器配置步骤(以标准ID为例) 三、不同模式的配置示例 四、高级配置技巧 五、调试与问题排查 六、关键计算公式 总结 概述 在STM32微控制器中,CAN过滤器可以配置为标识符屏蔽模式和标识符列表模…...
搜狗浏览器卸载教程
需求背景 今天发现geek居然无法卸载搜狗浏览器,作为一个老司机,这是不允许的。如果你使用geek或者windows的卸载,或者直接在它的安装包的Uninstall.exe中卸载,他走到100%就一直不动了。那玩意是假的。 卸载教程 结束 -----华丽的…...
Go 模块管理工具 `go mod tidy` 和 `go.sum` 文件详解
Go 模块管理工具 go mod tidy 和 go.sum 文件详解 引言 Go 语言自引入模块(module)系统以来,极大地简化了依赖管理和版本控制。go mod tidy 和 go.sum 文件是 Go 模块系统中的两个重要组成部分,它们共同确保项目的依赖项是最新的…...
音视频入门基础:RTP专题(9)——FFmpeg接收RTP流的原理和内部实现
一、引言 由《音视频入门基础:RTP专题(2)——使用FFmpeg命令生成RTP流》可以知道,推流端通过下面FFmpeg命令可以将一个媒体文件转推RTP,生成RTP流: ffmpeg -re -stream_loop -1 -i input.mp4 -vcodec cop…...
STM32 串口转 虚拟串口---实现USB转串口功能
一,USART与UART 区别 USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收/发送器 相较于UART:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)多了…...
【进程与线程】Linux 线程、同步以及互斥
每个用户进程有自己的地址空间。 线程是操作系统与多线程编程的基础知识。 系统为每个用户进程创建一个 task_struct 来描述该进程:该结构体中包含了一个指针指向该进程的虚拟地址空间映射表: 实际上 task_struct 和地址空间映射表一起用来表示一个进程…...
胶囊网络动态路由算法:突破CNN空间局限性的数学原理与工程实践
一、CNN的空间局限性痛点解析 传统CNN的瓶颈: 池化操作导致空间信息丢失(最大池化丢弃85%激活值)无法建模层次空间关系(旋转/平移等变换不敏感)局部感受野限制全局特征整合 示例对比: # CNN最大池化示例…...
当pcie设备变化时centos是否会修改网络设备的名称(AI回答)
当pcie设备变化时centos是否会修改网络设备的名称 在CentOS(以及其他基于Linux的操作系统)中,网络接口的命名通常遵循特定的规则,尤其是在使用PCIe设备(如网络适配器)时。网络接口的命名通常基于设备的物理…...
【人工智能】释放数据潜能:使用Featuretools进行自动化特征工程
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 特征工程是机器学习流程中至关重要的一步,它直接影响模型的性能。然而,手动特征工程既耗时又需要领域专业知识。Featuretools是一个强大的…...
docker批量pull/save/load/tag/push镜像shell脚本
目录 注意: 脚本内容 执行效果 注意: 以下脚本为shell脚本通过docker/nerdctl进行镜像独立打包镜像的相关操作脚本内仓库信息和镜像存取路径需自行更改需自行创建images.txt并填写值,并且与脚本位于同级目录下 [rootmaster01 sulibao]# l…...
对正则表达式说不!!!
可能大家都会和我一样,时常会遇到正则表达式,有时候会忘记某些字符而苦恼。今天就帮助大家克服它,虽然不多,但我认为掌握这些足够了,万变不离其宗,以不变应万变。 一、正则表达式内容分类 1. 字符类 [abc…...
Redis日志分析
主从同步尝试: 日志中多次出现“Master is currently unable to PSYNC but should be in the future: -NOMASTERLINK Can’t SYNC while not connected with my master”。这表明从服务器尝试与主服务器进行部分重同步(PSYNC),但由…...
【做一个微信小程序】校园地图页面实现
前言 上一个教程我们实现了小程序的一些的功能,有背景渐变色,发布功能有的呢,已支持图片上传功能,表情和投票功能开发中(请期待)。下面是一个更高级的微信小程序实现,包含以下功能:…...
Web后端 - Maven管理工具
一 Maven简单介绍 Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具。 Maven的作用 二 Maven 安装配置 依赖配置 依赖传递 依赖范围 生命周期 注意事项:在同一套生命周期中,当运行后面的阶段时,前面的阶段都…...
20250217-POMO笔记
文章目录 前言一、伪代码一:POMO Training二、伪代码二:POMO Inference三、POMO注意力模型3.1、自注意力机制3.2、AM模型 前言 以下主要讲解两个算法的伪代码以及注意力模型。 一、伪代码一:POMO Training POMO Training是POMO模型训练的伪…...
JavaEE-SpringBoot快速入门
文章目录 本节目标Maven什么是Maven创建一个Maven项目maven项目功能maven的依赖管理全球仓库, 私服, 本地服务器, 配置国内镜像 第一个SpringBoot项目创建项目运行SpringBoot程序 SpringBoot原理初步Web服务器 总结 本节目标 了解什么是maven, 配置国内源使用Springboot创建项…...
游戏引擎学习第107天
仓库:https://gitee.com/mrxiao_com/2d_game_2 回顾我们之前停留的位置 在这段内容中,讨论了如何处理游戏中的三维效果,特别是如何处理额外的“Z层”。由于游戏中的艺术资源是位图而不是3D模型,因此实现三维效果变得非常具有挑战性。虽然可…...
Sprinig源码解析
前言 Spring 框架是 Java 企业级开发的基石,其源码设计体现了模块化、扩展性和灵活性。以下从 IoC 容器、AOP 实现、核心模块和关键设计模式四个角度对 Spring 源码进行深度解析,帮助理解其底层机制。即使Spring会使用的人见得就能使用。 一、IoC 容器源…...
ComfyUI流程图生图原理详解
一、引言 ComfyUI 是一款功能强大的工具,在图像生成等领域有着广泛应用。本文补充一点ComfyUI 的安装与配置过程遇到的问题,并深入剖析图生图过程及相关参数,帮助读者快速入门并深入理解其原理。 二、ComfyUI 的安装与配置中遇到的问题 &a…...
使用右侧值现象来处理一个word导入登记表的需求
需求也简单,导word文件用户登记表,有各部门的十几个版本(为什么这么多?不知道)。这里说下谈下我的一些代码做法: 需求分析: 如果能解决java字段和各项填的值怎么配对的问题,那么就…...
《open3d pyqt》Alpha重建
《open3d pyqt》Alpha重建 一、效果展示二、qt设置2.1 主界面添加动作2.2 dialog 界面、布局如下:三、核心代码一、效果展示 二、qt设置 2.1 主界面添加动作 2.2 dialog 界面、布局如下: 并生成py文件,参考前述章节 三、核心代码 main.py文件增加 from Su...
深度解析HTTP/HTTPS协议:从原理到实践
深入浅出HTTP/HTTPS协议:从原理到实践 前言 在当今互联网世界中,HTTP和HTTPS协议如同空气般存在于每个网页请求的背后。作为开发者或技术爱好者,理解这些基础协议至关重要。本文将用六大板块,配合原理示意图和实操案例࿰…...
