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


Posted in NodeJs onMay 21, 2014

简介及资料

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)

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

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()去提升限值

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

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

NodeJs 相关文章推荐
nodejs爬虫抓取数据乱码问题总结
Jul 03 NodeJs
iPhone手机上搭建nodejs服务器步骤方法
Jul 06 NodeJs
NodeJS与HTML5相结合实现拖拽多个文件上传到服务器的实现方法
Jul 26 NodeJs
nodejs结合Socket.IO实现的即时通讯功能详解
Jan 12 NodeJs
nodeJS模块简单用法示例
Apr 21 NodeJs
NodeJS实现自定义流的方法
Aug 01 NodeJs
nodejs更新package.json中的dependencies依赖到最新版本的方法
Oct 10 NodeJs
详解从NodeJS搭建中间层再谈前后端分离
Nov 13 NodeJs
Nodejs中获取当前函数被调用的行数及文件名详解
Dec 12 NodeJs
NodeJS有难度的面试题(能答对几个)
Oct 09 NodeJs
ubuntu系统下使用pm2设置nodejs开机自启动的方法
May 12 NodeJs
跟我学Nodejs(一)--- Node.js简介及安装开发环境
May 20 #NodeJs
Nodejs使用mysql模块之获得更新和删除影响的行数的方法
Mar 18 #NodeJs
用nodejs实现PHP的print_r函数代码
Mar 14 #NodeJs
nodejs读取memcache示例分享
Jan 02 #NodeJs
利用NodeJS和PhantomJS抓取网站页面信息以及网站截图
Nov 18 #NodeJs
NodeJS的url截取模块url-extract的使用实例
Nov 18 #NodeJs
NodeJS url验证(url-valid)的使用方法
Nov 18 #NodeJs
You might like
谈谈新手如何学习PHP
2006/12/14 PHP
php通过COM类调用组件的实现代码
2012/01/11 PHP
Yii入门教程之Yii安装及hello world
2014/11/25 PHP
javascript 添加和移除函数的通用方法
2009/10/20 Javascript
zeroclipboard 单个复制按钮和多个复制按钮的实现方法
2014/06/14 Javascript
JavaScript中的继承之类继承
2016/05/01 Javascript
微信公众号菜单配置微信小程序实例详解
2017/03/31 Javascript
基于jQuery实现瀑布流页面
2017/04/11 jQuery
JS实现二维数组横纵列转置的方法
2018/04/17 Javascript
简述JS浏览器的三种弹窗
2018/07/15 Javascript
NodeJS使用Range请求实现下载功能的方法示例
2018/10/12 NodeJs
JS选取DOM元素常见操作方法实例分析
2018/12/10 Javascript
使用Layer组件弹出多个对话框(非嵌套)与关闭及刷新的例子
2019/09/25 Javascript
vue 解决form表单提交但不跳转页面的问题
2019/10/30 Javascript
AutoJs实现刷宝短视频的思路详解
2020/05/22 Javascript
解决antd的Form组件setFieldsValue的警告问题
2020/10/29 Javascript
使用Python判断质数(素数)的简单方法讲解
2016/05/05 Python
Django进阶之CSRF的解决
2018/08/01 Python
Python-Tkinter Text输入内容在界面显示的实例
2019/07/12 Python
python中将两组数据放在一起按照某一固定顺序shuffle的实例
2019/07/15 Python
python之拟合的实现
2019/07/19 Python
Python 字符串、列表、元组的截取与切片操作示例
2019/09/17 Python
Python调用Windows API函数编写录音机和音乐播放器功能
2020/01/05 Python
Anaconda使用IDLE的实现示例
2020/09/23 Python
python中requests模拟登录的三种方式(携带cookie/session进行请求网站)
2020/11/17 Python
celery在python爬虫中定时操作实例讲解
2020/11/27 Python
详解CSS3媒体查询响应式布局bootstrap 框架原理实战(推荐)
2020/11/16 HTML / CSS
戴森美国官网:Dyson美国
2016/09/11 全球购物
香港连卡佛百货官网:Lane Crawford
2019/09/04 全球购物
运动会稿件100字
2014/02/21 职场文书
2014年机关植树节活动方案
2014/02/27 职场文书
房屋维修协议书范本
2014/09/25 职场文书
个人作风建设心得体会
2014/10/22 职场文书
2016年国陪研修感言
2015/11/18 职场文书
详解Vue的列表渲染
2021/11/20 Vue.js
Pandas实现DataFrame的简单运算、统计与排序
2022/03/31 Python