Nodejs学习笔记(二)—事件模块
一.简介及资料
http://nodejs.org/api/events.html
http://www.infoq.com/cn/articles/tyq-nodejs-event
events是node.js 最重要的模块,events模块只提供了一个对象events.EventEmitter,EventEmitter 的核心是事件发射与事件监听器。
Node.js中大部分的模块,都继承自Event模块。
与DOM树上事件不同,不存在事件冒泡、逐层捕获等行为。
EventEmitter 支持若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
如何访问:require('events');
二.emitter.on(event, listener)
当然,也可以在cmd窗口中执行,如下所示 :

三.emitter.emit(event, [arg1], [arg2], [...])
示例进行了三次触发事件操作,其中some_events注册了监听,调用时emit函数会返回一个true,而other_events并没有注册监听,emit函数会返回一个false,表示该事件没有监听;当然也可以不用管这个返回值!
四.emitter.once(event, listener)
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
/*
EventEmitter.once(event, listener) 为事件注册一次性监听,触发一次后移除监听
参数1:event 字符串,事件名
参数2:回调函数
*/
ee.once('some_events', function(foo, bar) {
console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
});
console.log('第一轮');
ee.emit('some_events', 'Wilson', 'Zhong');
console.log('第二轮');
var isSuccess = ee.emit('some_events', 'Wilson', 'Zhong');
console.log(isSuccess);

从上面示例代码执行结果可以看出,用emitter.once给some_events注册一个监听后,分两轮调用emitter.emit触发,第二轮会返回false;这表示用emitter.once注册监听和用前面讲的emitter.on注册监听略有不同,emitter.once注册监听是一次性监听,当触发一次后,会移除该监听!当然,从名字上就看就比较明显了^_^!
五.emitter.removeListener(event, listener)
先来看一个失败的场景~~~
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
ee.on('some_events', function(foo, bar) {
console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
});
/*
看到API中removeListener移除方法时,以为应该是这样
但是结果^_^!!!!!
*/
ee.removeListener('some_events', function(){
console.log('成功移除事件some_events监听!');
});
console.log('第一轮');
ee.emit('some_events', 'Wilson', 'Zhong');

当我用emitter.on给some_events注册了一个监听后,我用emiiter.removeListener移除some_events的监听,随后再调用emitter.emit去触发,最后发现不是按我想像的在进行!为什么呢?
我理所当然的认为emiiter.removeListener第二个参数是个回调函数,API还是要认真看清楚啊!!!
下面再看个成功的场景~~~
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
var listener = function(foo,bar)
{
console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
}
var listener2= function(foo,bar)
{
console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );
}
var listener3= function(foo,bar)
{
console.log("第3个监听事件,参数foo=" + foo + ",bar="+bar );
}
ee.on('some_events', listener);
ee.on('some_events', listener2);
ee.on('some_events', listener3);
/*
EventEmitter.removeListener(event, listener) 移除指定事件的监听器
注意:该监听器必须是注册过的
PS:上一个例子之后以会失败,很大原因就是忽略了监听器,理所当然的认为传个事件名就OK了,所以就悲剧了!
*/
ee.removeListener('some_events', listener);
ee.removeListener('some_events', listener3);
ee.emit('some_events', 'Wilson', 'Zhong');

我用示例中写法,给some_events添加了三个监听,又移除了第一个和第三个监听,最后再用emitter.emit触发some_events,输出结果不难发现,用emitter.removeListener移除的第一个和第三个监听都没有再起作用,
想当然是害人地,原来emitter.removeListener的第二个参数是要移除的监听,而非移除成功后的回调函数……^_^!
六.emitter.removeAllListeners([event])
emitter.removeListener用过了,但一个事件可以有多个监听,需要全部移除时,一个个移除明显不是愉快的做法,不符合偷懒的天性!
让我们来体验一下emitter.removeAllListeners带来的便捷!
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
var listener = function(foo,bar)
{
console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
}
var listener2= function(foo,bar)
{
console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );
}
ee.on('some_events', listener);
ee.on('some_events', listener2);
ee.on('other_events',function(foo,bar)
{
console.log("其它监听事件,参数foo=" + foo + ",bar="+bar );
});
/*
EventEmitter.removeAllListeners([event]) 移除(批定事件)所有监听器
参数1:可选参数,event 字符串,事件名
*/
ee.removeAllListeners('some_events');
ee.emit('some_events', 'Wilson', 'Zhong');
ee.emit('other_events', 'Wilson', 'Zhong');

看看上面的执行结果,你会发现给some_events注册了两个监听;给other_events注册了一个监听;我调用emitter.removeAllListeners传了some_events事件名;
最后使用emitter.on函数触发some_events和other_events两个事件,最后发现some_events注册的两个监听都不存在,而other_events注册的监听还存在;
这表示当 emitter.removeAllListeners传用事件名作为参数时,为移除传入事件名的所有监听,而不会影响其它事件监听!
emitter.removeAllListeners可以不传用事件名参数,直接执行。
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
var listener = function(foo,bar)
{
console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
}
var listener2= function(foo,bar)
{
console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );
}
ee.on('some_events', listener);
ee.on('some_events', listener2);
ee.on('other_events',function(foo,bar)
{
console.log("其它监听事件,参数foo=" + foo + ",bar="+bar );
});
/*
EventEmitter.removeAllListeners([event]) 移除(批定事件)所有监听器
参数1:可选参数,event 字符串,事件名
*/
ee.removeAllListeners();
ee.emit('some_events', 'Wilson', 'Zhong');
ee.emit('other_events', 'Wilson', 'Zhong');

示例代码和传入参数时几乎一样,只是在调用emitter.removeAllListeners并没有传入指定事件名;
运行结果会发现some_events和other_events所有监听都不存在了,它会移除所有监听!(比较暴力的方法一般要慎用~~)
七.emitter.listeners(event)
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
var listener = function(foo,bar)
{
console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
}
var listener2= function(foo,bar)
{
console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );
}
ee.on('some_events', listener);
ee.on('some_events', listener2);
ee.on('other_events',function(foo,bar)
{
console.log("其它监听事件,参数foo=" + foo + ",bar="+bar );
});
/*
EventEmitter.listeners(event) //返回指定事件的监听数组
参数1:event 字符串,事件名
*/
var listenerEventsArr = ee.listeners('some_events');
console.log(listenerEventsArr.length)
for (var i = listenerEventsArr.length - 1; i >= 0; i--) {
console.log(listenerEventsArr[i]);
};
给some_events注册两个监听,调用emitter.listeners函数,传入some_events事件名,接收函数返回值;
从结果可以看出,返回值接收到some_events所有注册监听的集合!
八.emitter.setMaxListeners(n)
一个事件可以添加多个监听是没错,但Nodejs默认最大值是多少呢?
上面示例中我用个循环给some_events添加11个监听,执行代码,发现warning信息出现,并且提示的比较详细了,需要用emitter.setMaxListeners()去提升限值。
var EventEmitter = require('events').EventEmitter;
var ee = new EventEmitter();
/*
EventEmitter.setMaxListeners (n) 给EventEmitter设置最大监听
参数1: n 数字类型,最大监听数
超过10个监听时,不设置EventEmitter的最大监听数会提示:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added.
Use emitter.setMaxListeners() to increase limit.
设计者认为侦听器太多,可能导致内存泄漏,所以存在这样一个警告
*/
ee.setMaxListeners(15);
/*
给EventEmitter 添加11个监听
*/
for (var i = 10; i >= 0; i--) {
ee.on('some_events',function()
{
console.log('第'+ (i +1) +'个监听');
});
};

当我调用emitter.setMaxListeners传入15时,执行代码,warning信息不再出现;
emitter.setMaxListeners的作用是给EventEmitter设置最大监听数,感觉一般是不需要设置这个值,10个还不够用的情况应该是比较少了!
设计者认为侦听器太多会导致内存泄漏,所有就给出了一个警告!
九.其它
用的比较少的就不详细说了
1.EventEmitter.defaultMaxListeners
EventEmitter.defaultMaxListeners功能与setMaxListeners类似,给所有EventEmitter设置最大监听
setMaxListeners优先级大于defaultMaxListeners。
2.EventEmitter.listenerCount(emitter, event)
返回指定事件的监听数
3.特殊的事件Error
引用自Node.js开发指南:EventEmitter 定义了一个特殊的事件 error,它包含了“错误”的语义,我们在遇到 异常的时候通常会发射 error 事件。当 error 被发射时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。我们一般要为会发射 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。
4.事件的继承
有兴趣的可以自已看看:http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
此系列的源代码可到http://bijian1013.iteye.com/blog/2425085下载。
文章来源:https://www.cnblogs.com/zhongweiv/p/nodejs_events.html
Nodejs学习笔记(二)—事件模块的更多相关文章
- Webpack4 学习笔记二 CSS模块转换
前言 此内容是个人学习笔记,以便日后翻阅.非教程,如有错误还请指出 webpack 打包css模块 webpack是js模块打包器, 如果在入口文件引入css文件或其它的less.sass等文件,需要 ...
- nodejs学习笔记二(get请求、post请求、 querystring模块,url模块)
请求数据 前台:form.ajax.jsonp 后台:接受请求并返回响应数据 前台<= http协议 =>后台 常用的请求的方式: 1.GET 数据在url ...
- NodeJS学习笔记之MongoDB模块
其中还有,nodejs远程连接mysql数据库 一,开篇分析 这篇属于扩展知识篇,因为在下面的文章中会用到数据库操作,所以今天就来说说它(Mongodb模块). (1),简介 MongoDB是一个基于 ...
- NodeJS学习笔记 (21)事件机制-events(ok)
模块概览 events模块是node的核心模块之一,几乎所有常用的node模块都继承了events模块,比如http.fs等. 模块本身非常简单,API虽然也不少,但常用的就那么几个,这里举几个简单例 ...
- nodejs学习笔记二——链接mongodb
a.安装mongoose库用来链接mongodb数据库 安装mongodb数据库参考mongodb安装 前言(怨言) 本来是想安装mongodb库来链接mongodb的,命令行到nodejs工程目录: ...
- nodejs学习笔记<二>简单的node服务器
在环境搭建好后,就可以开始动手架设(node驱动)一个简单的web服务器. 首先,nodejs还是用js编写.先来看一段node官网上的实例代码. var http = require('http') ...
- nodejs学习笔记<二> 使用node创建基础服务器
创建服务器的 server.js 内容. var http = require("http"); // 引用http模块 http.createServer(function(re ...
- nodejs学习笔记二:解析express框架项目文件
上一章介绍了如何去创建一个express框架的工程项目,这章介绍一下express框架下的文件和用法解析,上一张我们创建的工程项目结构图如下: models是不属于原工程项目结构,为了实现数据模型后添 ...
- NodeJS学习笔记二
类声明和类表达式 ES6 中的类实际上就是个函数,而且正如函数的定义方式有函数声明和函数表达式两种一样,类的定义方式也有两种,分别是:类声明.类表达式. 类声明 类声明是定义类的一种方式,就像下面这样 ...
- NodeJS学习笔记之Connect中间件模块(一)
NodeJS学习笔记之Connect中间件模块(一) http://www.jb51.net/article/60430.htm NodeJS学习笔记之Connect中间件模块(二) http://w ...
随机推荐
- Docker搭建 MySQL 主从复制
为什么选 Docker 搭建主从复制需要两个以上的MySQL, 使用 Docker 非常方便.如果以前没用过,找个简单的文档看看,熟悉一下命令. 搭建过程 1.下载镜像 docker pull mys ...
- Win10系统下编译GEOS3.6.2
环境说明 1.Win10专业版.64位: 2.VS2012旗舰版: 3.cmake-3.9.0.64位: 资源准备 GEOS管网(http://trac.osgeo.org/geos)下载3.4.3版 ...
- MSMQ理论+实践(上)
关于MSMQ使用的文章,网上一搜一大把,为什么还要写呢?因为别人的终究是别人的,看一遍,只是过眼云烟罢了,还是要自己动手实践一下,才能把别人的变成自己的.再者就是网上大都是在一台电脑上写的demo,我 ...
- 使用vs code开发纸壳CMS并启用Razor智能提示
关于纸壳CMS 纸壳CMS是一个开源免费的,可视化设计,在线编辑的内容管理系统.基于ASP .Net Core开发,插件式设计: 下载代码 GitHub:https://github.com/Seri ...
- .net core获取服务器本地IP及Request访问端口
string str = (Request.HttpContext.Connection.LocalIpAddress.MapToIPv4().ToString() + ":" + ...
- AOP面向切面的基石——动态代理(一)
其实动态代理在Java里不是什么新技术了,早在java 1.2之后便通过 java.lang.reflect.InvocationHandler 加入了动态代理机制. 下面例子中,LancerEvol ...
- Yes,I know the way to learn Ens !
In recent years, translation has gone out of fashion as a way to learn a new language. A lot of peop ...
- SpringBoot程序远程debug
所谓的远程调试就是服务端程序运行在一台远程服务器上,我们可以在本地服务端的代码(前提是本地的代码必须和远程服务器运行的代码一致)中设置断点,每当有请求到远程服务器时时能够在本地知道远程服务端的此时的内 ...
- Python面试题整理-更新中
几个链接: 编程零基础应当如何开始学习 Python ? - 路人甲的回答 网易云课堂上有哪些值得推荐的 Python 教程? - 路人甲的回答 怎么用最短时间高效而踏实地学习 Python? - 路 ...
- 【OpenCV3】cvRound()、cvFloor()、cvCeil()函数详解
函数cvRound().cvFloor().cvCeil()都是按照一种舍入方式将浮点型数据转换为整型数据. cvRound():返回跟参数最接近的整数值,即四舍五入: cvFloor() :返回不 ...