前端开发系列090-Node篇之Event
一、EventEmitter介绍
Node中的event模块实现了事件处理相关功能,在该模块中定义了EventEmitter类。
在Node中,所有可能触发事件的对象都是继承了EventEmitter类的子类的实例对象,该类定义了诸多方法,譬如添加事件监听和移除事件监听以及自动触发事件等(通过下面的打印可以发现,这些方法均定义在原型对象上面)。
wendingding$ node
> console.dir(events,{showHidden:true,colors:true,depth:1})
{ [Function: EventEmitter]
[length]: 0,
[name]: 'EventEmitter',
[prototype]:
EventEmitter {
[constructor]: [Circular],
domain: undefined,
_events: undefined,
_maxListeners: undefined,
setMaxListeners: [Object],
getMaxListeners: [Object],
emit: [Object],
addListener: [Object],
on: [Object],
prependListener: [Object],
once: [Object],
prependOnceListener: [Object],
removeListener: [Object],
removeAllListeners: [Object],
listeners: [Object],
listenerCount: [Object],
eventNames: [Object] },
EventEmitter: [Circular],
usingDomains: true,
defaultMaxListeners: [Getter/Setter],
init: { [Function] [length]: 0, [name]: '', [prototype]: [Object] },
listenerCount: { [Function] [length]: 2, [name]: '', [prototype]: [Object] } }
EventEmitter结构说明
上面的代码是在REPL环境中直接通过console.dir方法来打印events整个模块的输出。为了方便理解,我这里另外再提供一份EventEmitter构造函数的具体实现作为对照和参考。
function EventEmitter() { EventEmitter.init.call(this); }
EventEmitter.usingDomains = false;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._eventsCount = 0; // 事件数量
EventEmitter.prototype._maxListeners = undefined; // 最大的监听器数
events模块中的EventEmitter指向的是模块自身。
wendingding$ node
> events == events.EventEmitter
true
EventEmitter构造函数身上有个比较重要的静态方法即init方法,该方法主要用来根据条件执行初始化操作,所谓的初始化具体点讲其实就是设置_events、_maxListeners,下面列出该方法的具体实现
EventEmitter.init = function() {
if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events)
{
this._events = Object.create(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
EventEmitter的defaultMaxListeners属性内部实现了Getter和Setter方法,该属性用来设置和获取指定事件可以绑定的最大事件处理函数数量,该属性默认值为10。对于默认事件绑定数量,我们可以通过在REPL环境中直接打印events.defaultMaxListeners来进行查看。此外,在EventEmitter原型对象上面,提供了setMaxListeners和getMaxListeners方法来对_maxListeners属性进行获取和设置。

二、Event相关方法
前文对events模块中的EventEmitter构造函数进行了简单介绍,接下来将主要说明具体事件监听绑定、移除和触发等相关的方法。
事件的监听(绑定)
当需要给指定对象添加事件监听(绑定事件处理函数)的时候,可以使用EventEmitter原型对象中的on方法或者是addListener方法,这两个方法的区别仅仅在于方法名,内部的实现一模一样,均调用events模块中的_addListener方法来实现。
_addListener方法核心过程
>① 验证监听器是否为函数对象。
>② 避免类型为`newListener`的事件类型,造成递归调用。
>③ 优化单个监听器的场景,不需使用额外的数组对象。
>④ 基于prepend参数的值,控制监听器的添加顺序。
这里先介绍事件监听(绑定)相关方法的语法,然后给出简短示例。
EventEmitterInstance.on(event,listener)EventEmitterInstance.addListener(event,listener)
参数说明 on方法和addListener方法接受两个参数,其中event代表的是事件的类型(事件的名称,譬如data、request等),而listener参数代表的是侦听器(事件处理函数)。
//备注:demo.js文件的内容
//001 导入模块
var http = require("http");
//002 创建server服务
var server = http.createServer();
//003 事件监听
// server.on("request",function(req,res){
server.addListener("request",function(req,res){
console.log("request--事件被触发");
console.log("req.url:",req.url);
//005 结束响应
res.end();
});
//004 开启监听
server.listen(4001,"127.0.0.1");
切换到当前所在目录,在终端中通过node demo.js命令执行上面的代码开启服务器端口监听,然后在浏览器中输入http://127.0.0.1:4001 地址,能够得到下面的打印输出:
wendingding$ node demo.js
request--事件被触发
req.url: /
request--事件被触发
req.url: /favicon.ico
备注 在给指定对象绑定事件监听的时候,支持给某类型的事件(譬如request)绑定多个处理函数,默认最多可以绑定10个且支持给指定对象绑定多种类型的事件监听(譬如request事件、end事件等)。绑定处理函数的数量可以通过getMaxListeners和setMaxListeners方法来操作。
var events = require("events");
//获取events模块(EventEmitter构造函数)的defaultMaxListeners属性值
console.log("defaultMaxListeners==",events.defaultMaxListeners);
console.log("默认getMaxListeners ==",rs.getMaxListeners());
rs.setMaxListeners(20)
console.log("设置getMaxListeners == 20");
console.log("最新getMaxListeners ==",rs.getMaxListeners());
//打印信息
defaultMaxListeners== 10
默认getMaxListeners == 10
设置getMaxListeners == 20
最新getMaxListeners == 20
除了上面介绍的on方法和addListener方法之外,once方法也能用来给指定的对象添加事件监听(绑定事件处理函数),区别在于once方法当事件处理函数执行一次后绑定就会立即被解除。
也就是该事件处理函数只会被执行一次。下面给出具体语法和简短示例:
EventEmitterInstance.once(event,listener)
//备注:once.js文件的内容
var fs = require("fs");
var rs = fs.createReadStream("Hi.text",{highWaterMark:10});
var data = [];
//001 监听rs实例对象的data事件,当事件触发的时候执行回调函数组织读取的Buffer数据
rs.addListener("data",function(chunk){
console.log("data...事件被触发");
data.push(chunk);
})
//002 监听rs实例对象的end事件,该事件当文件数据流读取完毕的时候触发
// 因为end事件只会被触发一次,所以完全可使用once方法来监听和绑定
rs.once("end",function(){
console.log("end····事件被触发");
var buf = Buffer.concat(data);
console.log(buf.toString());
});
//备注:执行once.js文件测试once方法的使用
wendingding$ node once.js
data...事件被触发
data...事件被触发
data...事件被触发
data...事件被触发
end····事件被触发
文顶顶:嗨,很高兴遇见你!
移除事件监听(解绑)
若需要解除指定对象的事件侦听,则可使用移除事件相关的方法。EventEmitter提供了removeListener方法和removeAllListeners方法来进行解绑操作,listeners方法可以获取当前对象中指定事件绑定的所有处理函数。下面先列出语法然后给出简短代码示例:
EventEmitterInstance.listeners(event)EventEmitterInstance.removeListener(event,listener)EventEmitterInstance.removeAllListeners(event)
//备注:removeListener.js文件的内容
var http = require("http");
var server = http.createServer();
function requestHandleOne (req,res) {
console.log("url == ",req.url);
console.log("request1····事件被触发");
res.end();
}
function requestHandleTwo (req,res) {
console.log("url == ",req.url);
console.log("request2····事件被触发");
res.end();
}
//给server对象添加request事件监听
server.addListener("request",requestHandleOne)
server.addListener("request",requestHandleTwo)
//开启服务端口监听
server.listen(4002,"127.0.0.1");
//获取事件监听处理函数
console.log("request事件处理函数列表:");
var handleList = server.listeners("request");
for(var key in handleList)
{
console.log("事件处理函数:",handleList[key].name);
}
console.log("移除前:",server.listenerCount("request"));
//移除事件监听(解除单个事件处理函数)
server.removeListener("request",requestHandleOne);
//移除事件监听(解除指定事件的所有处理函数)
//server.removeAllListeners("request");
console.log("移除后:",server.listenerCount("request"));
var events = require("events");
//获取指定对象中指定事件侦听的数量
var server_request_listenerCount = events.EventEmitter.listenerCount(server,"request")
console.log("server对象中request事件的侦听数量:",server_request_listenerCount);
代码说明
在上面的代码中我们首先创建了服务器sever对象,然后开启了服务器4002端口监听,并使用方法addListener为request事件添加两个侦听(分别是requestHandleOne和requestHandleTwo)函数。
server.listeners("request")函数用来获取sever对象上所有request事件处理函数列表。
server.listenerCount("request")函数用来获取sever对象上所有request事件处理函数的数量。
此外,在events模块的EventEmitter构造函数身上拥有一个listenerCount方法,该方法接收两个参数(对象,事件)以获取特定对象身上指定事件处理函数的数量。运行JavaScript代码,并在浏览器中访问:
wendingding$ node removeListener.js
request事件处理函数列表:
事件处理函数: requestHandleOne
事件处理函数: requestHandleTwo
移除前: 2
移除后: 1
server对象中request事件的侦听数量: 1
url == /
request2····事件被触发
url == /favicon.ico
request2····事件被触发
前端开发系列090-Node篇之Event的更多相关文章
- openlayers5-webpack 入门开发系列一初探篇(附源码下载)
前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...
- leaflet-webpack 入门开发系列一初探篇(附源码下载)
前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...
- 【Windows10 IoT开发系列】配置篇
原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...
- 旨在脱离后端环境的前端开发套件 - IDT Server篇
IDT,一个基于Nodejs的,旨在脱离后端环境的前端开发套件,目的就是能让前端开发完全脱离后端的环境,无论后端是什么模板引擎(主流),都能应付自如. IDT主要包括两大部分:Server + Bui ...
- cesium-webpack 入门开发系列一初探篇(附源码下载)
前言 cesium-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 we ...
- 前端开发【第2篇:CSS】
鸡血 样式的属性多达几千个,但别担心,按照80-20原则,常用的也就几十个,你完全可以掌握它. Css初识 HTML的诞生 早期只有HTML的时候为了让HTML更美观一点,当时页面的开发者会把颜色写到 ...
- [置顶]【实用 .NET Core开发系列】- 导航篇
前言 此系列从出发点来看,是 上个系列的续篇, 上个系列因为后面工作的原因,后面几篇没有写完,后来.NET Core出来之后,注意力就转移到了.NET Core上,所以再也就没有继续下去,此是原因之一 ...
- openlayers4 入门开发系列之风场图篇
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
- openlayers4 入门开发系列之热力图篇(附源码下载)
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
- Android Metro风格的Launcher开发系列第三篇
前言: 各位小伙伴,又到了每周更新文章了时候了,本来是周日能发出来呢,这不是赶上清明节吗,女王大人发话了,清明节前两天半陪她玩,只留给我周一下午半天时间写博客,哪里有女王哪里就有压迫呀有木有!好了闲话 ...
随机推荐
- Codeforces Round 1016 (Div. 3)题解
题目地址 https://codeforces.com/contest/2093 锐评 在所有题意都理解正确的情况下,整体难度不算太难.但是偏偏存在F这么恶心的题意,样例都不带解释一下的,根本看不懂题 ...
- Clion配置Fortran环境
1.安装CLion 下载链接:https://www.jetbrains.com/ 下载好后安装到指定目录即可 2.安装Fortran插件 3.编写程序 1)打开CLion,新建一个Fortran项目 ...
- Go工程选择开源分库分表中间件可用性测试
近期在寻找Go工程可以用的开源分库分表中间件,找了3个:ShardingSphere-Proxy,Kingshard,Gaea,下面给出测试过程和对比结果 ShardingSphere-Proxy h ...
- dbeaver导入sql脚本报错的排查—— ERROR 1366 (HY000) at line
描述 在使用dbeaver进行sql脚本导入的时候报了以下的错误. C:\Users\xxxx\AppData\Roaming\DBeaverData\drivers\clients\mysql_8\ ...
- SpringBoot项目创建的三种方式
目录 1 通过官网创建 2 通过IDEA脚手架创建 2.1 IDEA新建项目 2.2 起Group名字,选择Java版本,点击Next 2.3 选择Web依赖,选择Spring Web,确认Sprin ...
- 【MOOC】华中科技大学计算机组成原理慕课答案-第四章-存储系统(二)
待整理. 单选 1 32位处理器的最大虚拟地址空间为 A. 2G B. 8G C. 16G √D. 4G 2 在虚存.内存之间进行地址变换时,功能部件 ( )将地址从虚拟(逻辑)地址空间映射到物理地址 ...
- 用 Proxy 进一步提高 npm 安装速度
@charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...
- Median of Two Sorted Arrays---LeetCode进阶路④
题目描述 There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of th ...
- RBMQ案例五:主题模式
在之前的教程中,我们改进了日志系统.我们没有使用只能进行虚拟广播的扇出交换器,而是使用了直接交换器,并获得了选择性接收日志的可能性. 虽然使用直接交换改进了我们的系统,但它仍然有局限性--它不能基于多 ...
- RAG越来越不准?从Dify和ima知识库看元数据与标签如何让大模型更懂你
你是否有这样的经历:"知识库文档越来越多,知识库问答却越来越不靠谱,RAG检索到的都是一堆不相关的内容." 在这个信息爆炸的时代,我们不缺资料,缺的是找到"对的资料&qu ...