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


Posted in Javascript onFebruary 06, 2020

node.JS事件机制说明

多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(称为触发器)会周期性地触发命名事件来调用函数对象(监听器)。例如,一个net.Server对象会在每次有新连接时触发一个事件;一个 fs.ReadStream 会在文件被打开时触发一个事件;一个 stream会在数据可读时触发事件。

EventEmitter

EventEmitter 类由 events 模块定义和开放的,所有能触发事件的对象都是 EventEmitter 类的实例

var EventEmitter = require('events');
/*
{ [Function: EventEmitter]
 EventEmitter: [Circular],
 usingDomains: false,
 defaultMaxListeners: [Getter/Setter],
 init: [Function],
 listenerCount: [Function] }
 */
console.log(EventEmitter);

events模块的EventEmitter属性指向该模块本身

var events = require('events');
console.log(events.EventEmitter === events);//true
EventEmitter是一个构造函数,可以用来生成事件发生器的实例emitter
var EventEmitter = require('events');
var emitter = new EventEmitter();
/*
EventEmitter {
 domain: null,
 _events: {},
 _eventsCount: 0,
 _maxListeners: undefined }
 */
console.log(emitter);

方法

emitter.emit(eventName[, ...args])

eventName <any>

...args <any>

该方法按监听器的注册顺序,同步地调用每个注册到名为eventName事件的监听器,并传入提供的参数。如果事件有监听器,则返回true,否则返回false

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test1',function(){});
console.log(emitter.emit('test1'));//true
console.log(emitter.emit('test2'));//false

emitter.on(eventName, listener)

该方法用于添加listener函数到名为eventName的事件的监听器数组的末尾

eventName <any> 事件名

listener <Function> 回调函数

[注意]不会检查listener是否已被添加。多次调用并传入相同的eventName和listener会导致listener被添加与调用多次

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
});
emitter.on('test',function(){
  console.log(2);
});
emitter.emit('test');//1 2

该方法返回一个 EventEmitter 引用,可以链式调用

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
}).on('test',function(){
  console.log(2);
});
emitter.emit('test');//1 2

emitter.addListener(eventName, listener)

emitter.on(eventName, listener) 的别名

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.addListener('test',function(){
  console.log(1);
});
emitter.emit('test');//1

emitter.prependListener()

与on()方法不同,prependListener()方法可用于将事件监听器添加到监听器数组的开头

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
}).prependListener('test',function(){
  console.log(2);
});
emitter.emit('test');//2 1

emitter.once(eventName, listener)

该方法添加一个单次 listener 函数到名为 eventName 的事件。 下次触发 eventName 事件时,监听器会被移除,然后调用

eventName <any> 事件名

listener <Function> 回调函数

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
}).once('test',function(){
  console.log(2);
});
emitter.emit('test');//1 2
emitter.emit('test');//1

emitter.prependOnceListener()

该方法用于将事件监听器添加到监听器数组开头。下次触发eventName事件时,监听器会被移除,然后调用

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
}).prependOnceListener('test',function(){
  console.log(2);
});
emitter.emit('test');//2 1
emitter.emit('test');//1

emitter.removeAllListeners([eventName])

eventName <any>

移除全部或指定 eventName 的监听器,返回一个 EventEmitter 引用,可以链式调用

[注意]在代码中移除其他地方添加的监听器是一个不好的做法,尤其是当 EventEmitter 实例是其他组件或模块(如 socket 或文件流)创建的

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
}).removeAllListeners('test');
emitter.emit('test');//''

emitter.removeListener(eventName, listener)

eventName <any>

listener <Function>

从名为 eventName 的事件的监听器数组中移除指定的 listener

var EventEmitter = require('events');
var emitter = new EventEmitter();
function show(){
  console.log(1);
}
emitter.on('test',show).removeListener('test',show);
emitter.emit('test');//''

[注意]removeListener最多只会从监听器数组里移除一个监听器实例。如果任何单一的监听器被多次添加到指定eventName的监听器数组中,则必须多次调用removeListener才能移除每个实例

var EventEmitter = require('events');
var emitter = new EventEmitter();
function show(){
  console.log(1);
}
emitter.on('test',show).on('test',show).removeListener('test',show);
emitter.emit('test');//'1'

[注意]一旦一个事件被触发,所有绑定到它的监听器都会按顺序依次触发。这意味着,在事件触发后、最后一个监听器完成执行前,任何 removeListener() 或 removeAllListeners() 调用都不会从 emit() 中移除它们。 随后的事件会像预期的那样发生

因为监听器是使用内部数组进行管理的,所以调用它会改变在监听器被移除后注册的任何监听器的位置索引。 虽然这不会影响监听器的调用顺序,但意味着由 emitter.listeners() 方法返回的监听器数组副本需要被重新创建

var EventEmitter = require('events');
var emitter = new EventEmitter();
function show1(){
  console.log(1);
  emitter.removeListener('test',show2);
}
function show2(){
  console.log(2);
}
emitter.on('test',show1).on('test',show2);
emitter.emit('test');//1 2
emitter.emit('test');//1

设置

emitter.eventNames()

返回一个列出触发器已注册监听器的事件的数组。 数组中的值为字符串或符号

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.addListener('test1',function(){console.log(1);});
emitter.addListener('test2',function(){console.log(2);});
console.log(emitter.eventNames());//[ 'test1', 'test2' ]

emitter.listenerCount(eventName)

eventName <any> 正在被监听的事件名

返回正在监听名为 eventName 的事件的监听器的数量

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.addListener('test',function(){console.log(1);});
emitter.addListener('test',function(){console.log(1);});
console.log(emitter.listenerCount('test'));//2

emitter.listeners(eventName)

eventName <any>

返回名为 eventName 的事件的监听器数组的副本

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.addListener('test',function(){console.log(1);});
emitter.addListener('test',function(){console.log(2);});
console.log(emitter.listeners('test'));//[ [Function], [Function] ]
emitter.listeners('test')[0]();//1

emitter.getMaxListeners()

返回 EventEmitter 当前的最大监听器限制值

var EventEmitter = require('events');
var emitter = new EventEmitter();
console.log(emitter.getMaxListeners());//10

emitter.setMaxListeners(n)

默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告。 此限制有助于寻找内存泄露。 但是,并不是所有的事件都要被限为 10 个。 emitter.setMaxListeners() 方法允许修改指定的 EventEmitter 实例的限制。 值设为 Infinity(或 0)表明不限制监听器的数量。返回一个 EventEmitter 引用,可以链式调用

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){});
/*
Warning: Possible EventEmitter memory leak detected. 11 a listeners added. Use emitter.setMaxListeners() to increase limit
 */
var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.setMaxListeners(11);
emitter.on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){});

EventEmitter.defaultMaxListeners

每个事件默认可以注册最多10个监听器。单个EventEmitter实例的限制可以使用emitter.setMaxListeners(n)方法改变。所有EventEmitter实例的默认值可以使用EventEmitter.defaultMaxListeners属性改变

[注意]设置 EventEmitter.defaultMaxListeners 要谨慎,因为会影响所有EventEmitter 实例,包括之前创建的。因而,调用 emitter.setMaxListeners(n) 优先于 EventEmitter.defaultMaxListeners

var EventEmitter = require('events');
var emitter = new EventEmitter();
EventEmitter.defaultMaxListeners = 11;
emitter.on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){}).on('a',function(){});

node.JS事件注册与删除

'newListener' 事件

eventName <any> 要监听的事件的名称

listener <Function> 事件的句柄函数

EventEmitter 实例会在一个监听器被添加到其内部监听器数组之前触发自身的 'newListener' 事件

注册了 'newListener' 事件的监听器会传入事件名与被添加的监听器的引用。事实上,在添加监听器之前触发事件有一个微妙但重要的副作用: 'newListener' 回调中任何额外的被注册到相同名称的监听器会在监听器被添加之前被插入 

var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('newListener',function(){
  console.log(2);
})
emitter.on('test',function(){
  console.log(1);
})
emitter.emit('test');//2 1
var EventEmitter = require('events');
var emitter = new EventEmitter();
emitter.on('test',function(){
  console.log(1);
})
emitter.on('newListener',function(){
  console.log(2);
})
emitter.emit('test');//1

'removeListener' 事件

eventName <any> 事件名

listener <Function> 事件句柄函数

'removeListener' 事件在 listener 被移除后触发

var EventEmitter = require('events');
var emitter = new EventEmitter();
function show(){
  console.log(1);
}
emitter.on('removeListener',function(){
  console.log(2);//2
})
emitter.on('test',show).removeListener('test',show);
var EventEmitter = require('events');
var emitter = new EventEmitter();
function show(){
  console.log(1);
}
emitter.on('test',show).removeListener('test',show);
emitter.on('removeListener',function(){
  console.log(2);//''
})
var EventEmitter = require('events');
var emitter = new EventEmitter();
function show(){
  console.log(1);
}
emitter.removeListener('test',show);
emitter.on('removeListener',function(){
  console.log(2);//''

更多关于node.js事件的相关文章大家可以点击下面的相关链接

Javascript 相关文章推荐
使用JQUERY Tabs插件宿主IFRAMES
Jan 01 Javascript
一个简单的js鼠标划过切换效果
Jun 30 Javascript
JQuery扩展插件Validate—4设置错误提示的样式
Sep 05 Javascript
JQuery AJAX 中文乱码问题解决
Jun 05 Javascript
JS实现简易图片轮播效果的方法
Mar 25 Javascript
如何高效率去掉js数组中的重复项
Apr 12 Javascript
jQuery Easyui datagrid连续发送两次请求问题
Dec 13 Javascript
JavaScript使用FileReader实现图片上传预览效果
Mar 27 Javascript
Vue实现点击显示不同图片的效果
Aug 10 Javascript
javascript 对象 与 prototype 原型用法实例分析
Nov 11 Javascript
JS深入学习之数组对象排序操作示例
May 01 Javascript
js中Map和Set的用法及区别实例详解
Feb 15 Javascript
如何通过javaScript去除字符串两端的空白字符
Feb 06 #Javascript
ckeditor一键排版功能实现方法分析
Feb 06 #Javascript
JavaScript如何判断input数据类型
Feb 06 #Javascript
如何使用Jquery动态生成二级选项列表
Feb 06 #jQuery
CKEditor扩展插件:自动排版功能autoformat插件实现方法详解
Feb 06 #Javascript
JS实现盒子拖拽效果
Feb 06 #Javascript
JavaScript实现拖拽盒子效果
Feb 06 #Javascript
You might like
PHP 开源AJAX框架14种
2009/08/24 PHP
php数组函数序列之prev() - 移动数组内部指针到上一个元素的位置,并返回该元素值
2011/10/31 PHP
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
2013/06/29 PHP
window.onload 加载完毕的问题及解决方案(下)
2009/07/09 Javascript
jquery中获取select选中值的代码
2011/06/27 Javascript
js获取滚动距离的方法
2015/05/30 Javascript
javascript中if和switch,==和===详解
2015/07/30 Javascript
Bootstrap网格系统详解
2016/04/26 Javascript
JQuery控制图片由中心点逐渐放大效果
2016/06/26 Javascript
js实现背景图自适应窗口大小
2017/01/10 Javascript
Bootstrap免费字体和图标网站(值得收藏)
2017/03/16 Javascript
MvcPager分页控件 适用于Bootstrap
2017/06/03 Javascript
vuex state及mapState的基础用法详解
2018/04/19 Javascript
详解js访问对象的属性和方法
2018/10/25 Javascript
微信小程序五子棋游戏的棋盘,重置,对弈实现方法【附demo源码下载】
2019/02/20 Javascript
Vue 3.x+axios跨域方案的踩坑指南
2019/07/04 Javascript
[00:52]DOTA2国际邀请赛
2020/02/21 DOTA
跟老齐学Python之玩转字符串(2)
2014/09/14 Python
Python tkinter模块弹出窗口及传值回到主窗口操作详解
2017/07/28 Python
python调用百度地图WEB服务API获取地点对应坐标值
2019/01/16 Python
使用pandas把某一列的字符值转换为数字的实例
2019/01/29 Python
对Python 多线程统计所有csv文件的行数方法详解
2019/02/12 Python
python在回调函数中获取返回值的方法
2019/02/22 Python
Python的Tkinter点击按钮触发事件的例子
2019/07/19 Python
python 串口读取+存储+输出处理实例
2019/12/26 Python
Python CategoricalDtype自定义排序实现原理解析
2020/09/11 Python
python 解决Windows平台上路径有空格的问题
2020/11/10 Python
python 自定义异常和主动抛出异常(raise)的操作
2020/12/11 Python
浅谈CSS3中display属性的Flex布局的方法
2017/08/14 HTML / CSS
什么是事务?事务有哪些性质?
2012/03/11 面试题
浅谈react路由传参的几种方式
2021/03/23 Javascript
西北政法大学自主招生自荐信
2014/01/29 职场文书
初中毕业生自我评价
2015/03/02 职场文书
2015年销售人员工作总结
2015/04/07 职场文书
婚礼答谢词范文
2015/09/29 职场文书
情侣餐厅的创业计划书范本!
2019/07/26 职场文书