跟我学Nodejs(二)--- Node.js事件模块

简介及资料

  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)






 

代码如下:

/*
    调用events模块,获取events.EventEmitter对象
*/
var EventEmitter = require('events').EventEmitter;  
var ee = new EventEmitter();
/*
    EventEmitter.on(event, listener) 为事件注册一个监听
    参数1:event  字符串,事件名
    参数2:回调函数
*/
ee.on('some_events', function(foo, bar) {
    console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
});
console.log('第一轮');
ee.emit('some_events', 'Wilson', 'Zhong');
console.log('第二轮');
ee.emit('some_events', 'Wilson', 'Z');
EventEmitter.on(event, listener) 示例源码

emitter.emit(event, [arg1], [arg2], [...])






 

代码如下:

var EventEmitter = require('events').EventEmitter;  
var ee = new EventEmitter();
ee.on('some_events', function(foo, bar) {        
    console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );
});
/*
    EventEmitter.emit(event, [arg1], [arg2], [...])   触发指定事件
    参数1:event  字符串,事件名
    参数2:可选参数,按顺序传入回调函数的参数
    返回值:该事件是否有监听
*/
var isSuccess = ee.emit('some_events', 'Wilson', 'Zhong');
ee.on('some_events', function(foo, bar) {        
    console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );
});
ee.emit('some_events', 'zhong', 'wei');
var isSuccess2 = ee.emit('other_events', 'Wilson', 'Zhong');
console.log(isSuccess);
console.log(isSuccess2);
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(event, listener) 示例源码

从上面示例代码执行结果可以看出,用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.removeListener(event, listener) 示例失败场景源码

当我用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');
emitter.removeListener(event, listener) 示例成功场景源码

我用示例中写法,给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');
emitter.removeAllListeners 传入事件名参数示例源码

看看上面的执行结果,你会发现给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 不传参数示例源码

示例代码和传入参数时几乎一样,只是在调用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]);
};
emitter.listeners(event) 示例源码

给some_events注册两个监听,调用emitter.listeners函数,传入some_events事件名,接收函数返回值;

从结果可以看出,返回值接收到some_events所有注册监听的集合!

emitter.setMaxListeners(n)

一个事件可以添加多个监听是没错,但Nodejs默认最大值是多少呢?






 

代码如下:

var EventEmitter = require('events').EventEmitter;  
var ee = new EventEmitter();
/*
     给EventEmitter 添加11个监听
*/
for (var i = 10; i >= 0; i--) {
    ee.on('some_events',function()
    {
        console.log('第'+ (i +1) +'个监听');
    });
};
添加N个监听示例源码

上面示例中我用个循环给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 示例源码

当我调用emitter.setMaxListeners传入15时,执行代码,warning信息不再出现;

emitter.setMaxListeners的作用是给EventEmitter设置最大监听数,感觉一般是不需要设置这个值,10个还不够用的情况应该是比较少了!

设计者认为侦听器太多会导致内存泄漏,所有就给出了一个警告!

其它...

用的比较少的就不详细说了

EventEmitter.defaultMaxListeners

EventEmitter.defaultMaxListeners功能与setMaxListeners类似,
    给所有EventEmitter设置最大监听
    setMaxListeners优先级大于defaultMaxListeners

EventEmitter.listenerCount(emitter, event)

返回指定事件的监听数

特殊的事件Error

引用自Node.js开发指南:EventEmitter 定义了一个特殊的事件 error,它包含了“错误”的语义,我们在遇到 异常的时候通常会发射 error 事件。当 error 被发射时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。我们一般要为会发射 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。

事件的继承

以后归到util里再讲一下吧,有兴趣的可以自已看看 http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

(0)

相关推荐

  • 跟我学Nodejs(三)--- Node.js模块

    简介及资料 通过Node.js的官方API可以看到Node.js本身提供了很多核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,可以require('模块名')去获取:核心模块具有最高的加载优先级(有模块与核心模块同名时会体现) (本次主要说自定义模块) Node.js还有一类模块为文件模块,可以是JavaScript代码文件(.js作为文件后缀).也可以是JSON格式文本文件(.json作为文件后缀).还可以是编辑过的C/C++文件(.node作为文件后

  • node.js使用require()函数加载模块

    详细说明均以写在注释之中,这里就不啰嗦了,小伙伴们自己详细看吧,千万别吧注释当成空气了. 复制代码 代码如下: /*在node中,可以使用require()函数来加载模块.  * require函数使用一个参数,参数值可以带有完整路径的模块的文件名,也可以为模块名.当使用node中提供的模块时,在require函数中只需要指定模块名即可.  * */ //建立一个页面2.js;代码如下 var name="思思博士"; exports.name=name; //建立一个页面1.js;代

  • NODE.JS加密模块CRYPTO常用方法介绍

    使用require('crypto')调用加密模块. 加密模块需要底层系统提供OpenSSL的支持.它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接. 该模块还提供了一套针对OpenSSL的hash(哈希),hmac(密钥哈希),cipher(编码),decipher(解码),sign(签名)以及verify(验证)等方法的封装. crypto.createCredentials(details) 创建一个凭证对象,可选参数details为一个带键值的字典: key

  • Node.js模块加载详解

    JavaScript是世界上使用频率最高的编程语言之一,它是Web世界的通用语言,被所有浏览器所使用.JavaScript的诞生要追溯到Netscape那个时代,它的核心内容被仓促的开发出来,用以对抗Microsoft,参与当时白热化的浏览器大战.由于过早的发布,无可避免的造成了它的一些不太好的特性. 尽管它的开发时间很短,但是JavaScript依然具备了很多强大的特性,不过,每个脚本共享一个全局命名空间这个特性除外. 一旦Web页面加载了JavaScript代码,它就会被注入到全局命名空间,

  • 在Windows上安装Node.js模块的方法

    不过有消息称Microsoft已经联系Node.js官方,相信很快会有改善. 那么在不安装Cygwin的情况下,是否可以在Windows上搭建Node.js环境进行试验开发哪?我以Node.js + express做了个简单测试,基本可行. 步骤如下: 1. 下载Node.js官方非稳定版Windows可执行程序: http://nodejs.org/#download 我在试验中使用了0.5.7版本:http://nodejs.org/dist/v0.5.7/node.exe 2. 创建c:\

  • Node.js 的模块知识汇总

    在写 Node.js 应用程序的时候,你确实可以把所有代码放在巨大原 index.js 文件中,不在乎你的应用程序会变得多大多复杂.Node.js 解释器不会在意这个事情.但在代码组织方面,你很快就会陷入混乱,不能理解代码,而且难以调试.所以,作为一个人,你应该关心代码的结构.这就是使用模块的原因. 你可以把 Node.js 模块当作 JavaScript 库 -- 是整体代码中你想放在一起的某个部分(比如,函数集),你会想把这部分代码相对独立于代码库中的其它部分,可以把事情区分清楚. 就们我们

  • 用C/C++来实现 Node.js 的模块(一)

    N久之前的一个坑--用 Node.js 来重构 NBUT 的 Online Judge,包括评测端也得重构一遍.(至于什么时候完成大家就不要关心了,(/‵Д′)/~ ╧╧ 总之我们现在要做的其实简而言之就是--用C/C++来实现 Node.js 的模块. 准备工作 工欲善其事,必先~~耍流氓~~利其器. node-gyp 首先你需要一个 node-gyp 模块. 在任意角落,执行: 复制代码 代码如下: $ npm install node-gyp -g 在进行一系列的 blahblah 之后,

  • 跟我学Nodejs(二)--- Node.js事件模块

    简介及资料 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 支持若干

  • node.js事件循环机制及与js区别详解

    目录 一.是什么 二.流程 三.题目 一.是什么 在浏览器事件循环(opens new window)中,我们了解到javascript在浏览器中的事件循环机制,其是根据HTML5定义的规范来实现 而在NodeJS中,事件循环是基于libuv实现,libuv是一个多平台的专注于异步IO的库,如下图最右侧所示: 上图EVENT_QUEUE 给人看起来只有一个队列,但EventLoop存在6个阶段,每个阶段都有对应的一个先进先出的回调队列 二.流程 上节讲到事件循环分成了六个阶段,对应如下: tim

  • Node.js事件循环(Event Loop)和线程池详解

    Node的"事件循环"(Event Loop)是它能够处理大并发.高吞吐量的核心.这是最神奇的地方,据此Node.js基本上可以理解成"单线程",同时还允许在后台处理任意的操作.这篇文章将阐明事件循环是如何工作的,你也可以感受到它的神奇. 事件驱动编程 理解事件循环,首先要理解事件驱动编程(Event Driven Programming).它出现在1960年.如今,事件驱动编程在UI编程中大量使用.JavaScript的一个主要用途是与DOM交互,所以使用基于事件

  • 深入理解Node.js 事件循环和回调函数

    本文详细的介绍了Node.js 事件循环和Node.js回调函数,废话不多说了,具体看下面把.  一.Node.js 事件循环 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高.Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发.Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现.Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观

  • 深入浅析Node.js 事件循环

    Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. (来源于Javascript是单线程又是异步的,但是这种语言有个共同的特点:它们是 event-driven 的.驱动它们的 event 来自一个异构的平台.) Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件

  • Node.js net模块功能及事件监听用法分析

    本文实例讲述了Node.js net模块功能及事件监听用法.分享给大家供大家参考,具体如下: net模块 对比C语言的网络编程,Node.js有更加简便的开发模式与模块提供.它就是net模块 在需要使用的时候只需要require("net")就可以引入模块了. var net = require("net"); 服务端编程 引入模块的前提下: 1. 创建一个新的TCP或IPC服务 var server = net.createServer(function(clie

  • 从Node.js事件触发器到Vue自定义事件的深入讲解

    Node.js中的事件触发器所引发的思考 今天在看 Node.js 文档的时候讲到事件触发器,其中的 emit 方法让我想到了 Vue 中的自定义事件,借此我对 Vue 又有了新的理解,所以将我的理解记录下来,留作学习笔记. Node.js中的事件触发器 Node.js 为我们提供了一个事件模块:EventEmitter,我们可以用它来处理事件 const EventEmitter = require('events') const eventEmitter = new EventEmitter

  • Node.js 事件循环详解及实例

     Node.js  事件循环详解及实例 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数. Node.js 有多个内置的事件,我们可以

  • 深入浅析Node.js 事件循环、定时器和process.nextTick()

    什么是事件循环 尽管JavaScript是单线程的,但通过尽可能将操作放到系统内核执行,事件循环允许Node.js执行非阻塞I/O操作. 由于现代大多数内核都是多线程的,因此它们可以处理在后台执行的多个操作. 当其中一个操作完成时,内核会告诉Node.js,以便可以将相应的回调添加到 轮询队列 中以最终执行. 我们将在本主题后面进一步详细解释. 事件循环解释 当Node.js启动时,它初始化事件循环,处理提供的输入脚本(或放入 REPL ,本文档未涉及),这可能会进行异步API调用,调度计时器或

  • node.JS事件机制与events事件模块的使用方法详解

    node.JS事件机制说明 多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(称为触发器)会周期性地触发命名事件来调用函数对象(监听器).例如,一个net.Server对象会在每次有新连接时触发一个事件:一个 fs.ReadStream 会在文件被打开时触发一个事件:一个 stream会在数据可读时触发事件. EventEmitter EventEmitter 类由 events 模块定义和开放的,所有能触发事件的对象都是 EventEmitter 类的实例

随机推荐