事件是具有软件或硬件意义的动作。 它们是由于用户活动(例如鼠标单击或击键)或直接来自系统(例如错误或通知)而发出的。

JavaScript 语言使我们能够通过在事件处理程序中运行代码来响应事件。 由于 Node.js 基于 JavaScript,因此它在其事件驱动架构中利用了此功能。

在本文中,我们将讨论什么是事件发射器以及为什么要使用它们,以及如何构建自定义事件发射器。 让我们开始吧!

  • 系统事件与自定义事件

    • 1.系统事件

    • 2.自定义事件

  • 什么是事件发射器?

  • 为什么使用事件发射器?

  • 内的班级成员 EventEmitter

  • 自定义事件发射器的一般模式

  • 在 Node.js 中构建自定义事件发射器

    • 创建事件发射器函数构造函数

    • 向事件发射器原型添加方法

  • 添加更多事件方法

    • 这 addListener方法

    • 这 listenersCount方法

系统事件与自定义事件

中的事件 Node.js 是我们可以响应的应用程序中发生的操作。 Node.js 中有两种不同类型的事件,我们将在本文中介绍这两种类型:

1.系统事件

系统事件发生在 Node.js 核心的 C++ 端,并由 Node.js 中使用的名为 libuv 的 C 库处理。

libuv 库处理计算机系统内部发生的低级事件,本质上是来自操作系统的低级事件,例如从互联网接收数据、完成读取文件等。

因为 Node.js 程序的流程是由事件(事件驱动编程)决定的,所以所有的 I/O 请求最终都会产生一个完成/失败事件。

旁注:JavaScript 没有处理系统事件的内置功能。

2.自定义事件

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

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

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

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


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


什么是事件发射器?

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

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

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

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

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

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对象是:

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

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

  3. 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 notif(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 Emitterthis.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 notif (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 操作/状态。

如何构建自定义 Node.js 事件发射器相关推荐

  1. Node.js 系列:构建原生 Node.js 应用

    原生 Node.js 应用 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效 Nod ...

  2. Linux事件循环阻塞,深入浅析Node.js 事件循环、定时器和process.nextTick()

    什么是事件循环 尽管JavaScript是单线程的,但通过尽可能将操作放到系统内核执行,事件循环允许Node.js执行非阻塞I/O操作. 由于现代大多数内核都是多线程的,因此它们可以处理在后台执行的多 ...

  3. 自制chatroom_构建由Node.js驱动的Chatroom Web App:入门

    自制chatroom 本文是Microsoft的Web开发技术系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. 这个Node.js教程系列将帮助您构建完全部署在云中的由Node.js ...

  4. node.js 事件循环

    node.js是单线程的应用程序,但是他可能通过event和callback来支持并发.所有的node.js都是单线程的,也是异步的,他们使用调用异步函数来维持高并发.Node使用观察者模式.Node ...

  5. 八七、Node.js事件循环与多进程

    nodejs事件循环与多进程 why 事件循环对于深入理解nodejs异步至关重要 fs, net,http,events 事件循环是企业面试中的最高频考题之一 能驾驭nodejs多进程是一名资深前端 ...

  6. 在openshift上自定义node.js的版本

    https://github.com/ramr/nodejs-custom-version-openshift 由于是线上服务器,一步一步来: 先把上面的工程拉下来,覆盖到初始化的工程里,提交,让服务 ...

  7. Node.js学习五(事件)

    文章目录 一.Node.js事件循环 二.事件驱动程序 三.事件触发器 1.EventEmitter类 2.事件触发器的方法 (1)EventEmitter类的on方法 (2)EventEmitter ...

  8. 在Node.js中使用事件,监听器,定时器和回调

    Node.js通过其强大的事件驱动模型提供了可扩展性和性能,本篇文章的重点是理解该模型,以及它是如何不同于大部分Web服务器采用的传统线程模型的.了解事件模型至关重要,因为它可能迫使你改变设计应用程序 ...

  9. Node.js中事件的循环

    Node.js 事件循环 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用, ...

最新文章

  1. linux 脚本发邮件短信,shell 监控脚本 短信告警
  2. The RSpec Book笔记《一》初步认识TDD,BDD,RSpec,Cucumber
  3. 约瑟夫问题(丢手帕问题)
  4. Java18-day09【字节缓冲流、字符流、编码表、字符串与字符流中的编码解码问题、字符流读写数据的方式、字符缓冲流、IO流小结】
  5. 你买过假芯片吗?元器件专家为您揭秘假冒芯片的套路!
  6. SSH框架整合——基于注解
  7. c if sortable html,sortable.js中文文档
  8. java webservice 接收数据_WebService客户端,接收数据解析存入数据库
  9. Java 数据结构与算法面试 链表
  10. parallels desktop big sur 网络_初中生数学网络学习哪个好
  11. “光伏热”背后存隐忧 竞价上网倒逼产业升级
  12. 机器学习基础(五十二)—— 朴素贝叶斯细节
  13. ASP.NET WebAPI构建API接口服务实战演练
  14. 上海中环C位出道,自动驾驶天团横「扫」北上广
  15. 华为数通HCIA笔记(OSI七层)
  16. 酒店旅业治安管理系统接口开发
  17. speedoffice(Excel)表格如何添加边框?
  18. Photon网络游戏开发——PUN2简介
  19. java队列打印杨辉三角_数组打印杨辉三角与队列打印杨辉三角
  20. 2017年阳光私募基金一季度报告

热门文章

  1. android非法字符 ufeff,Android 非法字符:'/ufeff'
  2. 三棱柱以及多棱柱的实现
  3. 女人,你是爱情呼叫转移中的哪一个?
  4. ARM 仿真器种类与概念(JTAG、SWD、JLink、ULink、ST-Link)
  5. QQ空间迁移_【raid6raid10性能对比】
  6. 隐藏起来的WiFi也能被查找到?看看用Python如何实现的!
  7. antd-vue上传文件,并读取文件内容
  8. Windows系统文件名的最大长度
  9. HTML5-web通信之 Cross-Document Messaging(XDM) Channel Messaging
  10. 你会在终端下快速获取公网 IP 地址吗,学会这些技巧后你就游刃有余了!