转载:http://www.cnblogs.com/zhongweiv/p/nodejs_events.html

目录

  • 简介及资料
  • 事件常用函数及使用
    • emitter.on(event, listener)
    • emitter.emit(event, [arg1], [arg2], [...])
    • emitter.once(event, listener)
    • emitter.removeListener(event, listener)
    • emitter.removeAllListeners([event])
    • emitter.listeners(event)
    • emitter.setMaxListeners(n)
    • 其它...

简介及资料

  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(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.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) 示例成功场景源码

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 传入事件名参数示例源码

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 不传参数示例源码

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

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 = ; i >= ; i--) {
ee.on('some_events',function()
{
console.log('第'+ (i +) +'个监听');
});
}; 添加N个监听示例源码

添加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(); /*
给EventEmitter 添加11个监听
*/
for (var i = ; i >= ; i--) {
ee.on('some_events',function()
{
console.log('第'+ (i +) +'个监听');
});
}; emitter.setMaxListeners 示例源码

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

nodeJS学习(10) --- 事件模块的更多相关文章

  1. nodejs学习:net模块

    官方API文档地址:https://nodejs.org/api/net.html 创建一个server.js var net = require('net'); var PORT = 8099; v ...

  2. nodeJs学习-01 http模块

    http模块基础: const http = require("http"); //引入http系统模块 var server = http.createServer(functi ...

  3. NodeJS学习笔记 (23)模块机制-module

    https://github.com/chyingp/nodejs-learning-guide

  4. nodeJs学习-10 模板引擎 ejs语法案例

    ejs语法案例 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...

  5. nodeJs学习-02 fs模块(文件操作)

    读文件: const fs = require('fs'); //读文件(异步) readFile(文件名,回调函数) fs.readFile('section03/testData/aaa.txt' ...

  6. 自己实现一个javascript事件模块

    nodejs中的事件模块 nodejs中有一个events模块,用来给别的函数对象提供绑定事件.触发事件的能力.这个别的函数的对象,我把它叫做事件宿主对象(非权威叫法),其原理是把宿主函数的原型链指向 ...

  7. Backbone事件模块源码分析

    事件模块Backbone.Events在Backbone中占有十分重要的位置,其他模块Model,Collection,View所有事件模块都依赖它.通过继承Events的方法来实现事件的管理,可以说 ...

  8. nodejs事件模块

    nodejs 事件模块 events 只有一个对象 EventEmitter . var EventEmitter = require('events').EventEmitter;var life ...

  9. 深入理解nodejs的异步IO与事件模块机制

    node为什么要使用异步I/O 异步I/O的技术方案:轮询技术 node的异步I/O nodejs事件环 一.node为什么要使用异步I/O 异步最先诞生于操作系统的底层,在底层系统中,异步通过信号量 ...

随机推荐

  1. Linux命令安装vnc服务端与vnc的客户端

    第一歩:运行命令 yum install tigervnc-server -y 第二歩:安装telnet 第三歩:运行vncserver,创建桌面 vncserver -kill :1  删除桌面1的 ...

  2. EasyUI获取正在编辑状态行的索引

    function getRowIndex(target){ var tr = $(target).closest("tr.datagrid-row"); return paseIn ...

  3. php微信分享demo

    php微信分享demo //定义JSSDK类 <?php class JSSDK { private $appId; private $appSecret; private $redis; pu ...

  4. Python 正则表达式 匹配次数

    管道可以匹配多个正则表达式中的一个 >>> >>> m=re.search(r'Batman|Tina Fey','Batman and Tina Fey')> ...

  5. thinkphp 5数据库操作

    1.原生sql $options=Db::table('__MALL_POST__') ->alias('m') ->join('__MALL_CATEGORY_VALUE__ v','m ...

  6. web项目中无法开启或404

    404找不到页面,可能是spring的bean自动注入有了问题,例如org.springframework.beans.factory.BeanCreationException:可以检查配置文件的s ...

  7. 【转载】MQTT的学习之Mosquitto集群搭建

    本文出自:http://www.cnblogs.com/yinyi521/p/6087215.html 文章钢要: 1.进行双服务器搭建 2.进行多服务器搭建 一.Mosquitto的分布式集群部署 ...

  8. debug模式开启会做哪些事(源码分析)

    以往开发中不管是django框架下开发还是其它框架下开发, 只知道在开发阶段要开启debug模式, 却一直没有深究它会我们做哪些事, 今天使用tornado时偶然看到源码中写的很清楚,故写下来加深印象 ...

  9. 使用 CAST

    使用 CAST: CAST ( expression AS data_type ) 使用 CONVERT: CONVERT (data_type[(length)], expression [, st ...

  10. 水题:HDU-1088-Write a simple HTML Browser(模拟题)

    解题心得: 1.仔细读题,细心细心...... 2.题的几个要求:超过八十个字符换一行,<br>换行,<hr>打印一个分割线,最后打印一个新的空行.主要是输出要求比较多. 3. ...