前端开发系列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开发系列第三篇
前言: 各位小伙伴,又到了每周更新文章了时候了,本来是周日能发出来呢,这不是赶上清明节吗,女王大人发话了,清明节前两天半陪她玩,只留给我周一下午半天时间写博客,哪里有女王哪里就有压迫呀有木有!好了闲话 ...
随机推荐
- 搭建Zookeeper、Kafka集群
搭建Zookeeper.Kafka集群 Zookeeper.Kafka集群系统环境配置 配置IP ssh root@192.168.1.190 "rm -rf /etc/machine-id ...
- nginx代理静态页面添加二级目录
location /wash { # root html; alias /home/cxq/wash-html/dist; index index.html index.htm; try_files ...
- MySQL 的覆盖索引是什么?
MySQL 的覆盖索引是什么? 覆盖索引(Covering Index)是指索引本身包含了查询所需的所有字段数据,从而无需再回表查询的数据访问方式.这种优化能够显著提升查询性能. 1. 覆盖索引的特点 ...
- 安装MVN出现 Error: JAVA_HOME is set to an invalid directory.的解决方法
出现 Error: JAVA_HOME is set to an invalid directory.的解决方法 解决: 将JAVA_HOME = "D:/Java/jdk1.6.0_12/ ...
- 操作系统综合题之“银行家算法,计算各资源总数和Need还需要数量和解释什么是安全状态以及银行家进阶题(额外提出资源请求计算是否满足)”
一.问题:某系统在某时刻的进程和资源状态如下表所示: 进程 Allocation(已分配资源数) (A B C D) Max(最大需要资源数) (A B C D) Avaliable(可用资源数) ( ...
- Flask 中用 dbutils 实现数据库连接池
之前用 dbutils 来实现数据库连接池, 这里将其封装为一个自定义类并在 flask 中实际应用一下, 在实际场景中肯定是多页面接口, 这也就涉及到 python 的 import 问题, 就个人 ...
- Web前端入门第 49 问:CSS offset 路径动画演示
什么是路径动画? 随手画一条不规则的线,让元素按照这条不规则的线运动起来,这就是所谓的路径动画. 前面说过的动画都只能针对某一个 CSS 属性,要想实现路径动画可没办法,路径动画必须借助 CSS3 的 ...
- Web前端入门第 50 问:CSS 内容溢出怎么处理?
溢出:盒模型装不下内容的时候,超出盒子大小的内容就称之为内容溢出,这里的内容又分为盒模型和文本,所以 CSS 在处理溢出时候也分为文本和盒模型两种情况. 正常情况内容溢出应该换行自动撑开盒子大小,但某 ...
- CentOS7.6安装RabbitMQ
1.CentOS7.6安装RabbitMQ yum install -y socat yum install -y erlang 2.安装rabbitmq yum install rabbitmq-s ...
- TVM Pass优化 -- InferType 类型推导
定义(What) InferType,类型推断,顾名思义,给表达式进行类型的推断 直接上代码 import tvm from tvm import relay import numpy as np d ...