events模块是node的核心模块,几乎所有常用的node模块都继承了events模块,比如http、fs等。本文将详细介绍nodeJS中的事件机制

EventEmitter

多数 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();
emitter.on('test',function(){
console.log(1);
}).prependListener('test',function(){
console.log(2);
});
emitter.emit('test');//2 1

注意: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

nodeJS中的事件机制的更多相关文章

  1. NodeJS 中的事件循环,读了这篇就全懂了

    事件循环是 NodeJS 处理非阻塞 I/O 操作的和核心机制.NodeJS 的事件循环脱胎于 libuv 的事件循环,因此,要搞清楚 NodeJS 的事件循环,还需要先了解 libuv 的事件循环是 ...

  2. jQuery中的事件机制深入浅出

    昨天呢,我们大家一起分享了jQuery中的样式选择器,那么今天我们就来看一下jQuery中的事件机制,其实,jQuery中的事件机制与JavaScript中的事件机制区别是不大的,只是,JavaScr ...

  3. Tomcat与Spring中的事件机制详解

    最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认 ...

  4. Spring 中的事件机制

    说到事件机制,可能脑海中最先浮现的就是日常使用的各种 listener,listener去监听事件源,如果被监听的事件有变化就会通知listener,从而针对变化做相应的动作.这些listener是怎 ...

  5. NodeJS中的事件

    /** * Created by xiwu.xxw on 2015/7/22. */ /** * EventEmitter 的每个事件由一个事件名和若干个参数组成, * 事件名是一个字符串,通常表达一 ...

  6. javascript 中的事件机制

    1.javascript中的事件. 事件流 javascript中的事件是以一种流的形式存在的. 一个事件会也有多个元素同时响应. 有时候这不是我们想要的效果, 我们只是需要某个特定的元素相应我们的绑 ...

  7. libevent中的事件机制

    libevent是事件驱动的网络库,事件驱动是他的核心,所以理解事件驱动对于理解整个网络库有很重要的意义.       本着从简入繁,今天分析下单线程最简单的事件触发.通过sample下的event- ...

  8. Flex中利用事件机制进行主程序与子窗体间参数传递

    在开发具有子窗体,或者itemrenderer的应用时,常常涉及到子窗体向父窗体传递参数或者从itemrenderer内的控件向外部的主程序传递参数的需求.这些都可以通过事件机制这一统一方法加以解决. ...

  9. nodejs 中自定义事件

    经常看到 req.on('error', function(){...}); 这种代码. 在nodejs中,可以使用 EventEmitter来实现. 具体的关键词有如下几个: var reqEven ...

随机推荐

  1. robot 如何定义用户关键字、变量

    1.用户关键字,使用robot语法定义的关键字 2.系统关键字  自带的 3.资源文件,自己定义的关键字 4.变量 自己定义的关键字,需单独建一个资源文件 自己写的关键字,需写在***Keywords ...

  2. jmeter简单的压力测试

    Jmeter是一个非常好用的压力测试工具.  Jmeter用来做轻量级的压力测试,非常合适,只需要十几分钟,就能把压力测试需要的脚本写好.相比LR来说操作简单方便,关键是免费,基于JAVA开发,所以需 ...

  3. poi 1182

    食物链 || 带权并查集 0:同类 1:吃 2:被吃 #include <cstdio> using namespace std; const int maxn=5e4+3; int f[ ...

  4. 【NOIP2012模拟8.7】JZOJ2020年8月8日提高组T1 奶牛编号

    [NOIP2012模拟8.7]JZOJ2020年8月8日提高组T1 奶牛编号 题目 作为一个神秘的电脑高手,Farmer John 用二进制数字标识他的奶牛. 然而,他有点迷信,标识奶牛用的二进制数字 ...

  5. Linux之【安装系统后的调优和安全设置】

    关闭SElinux功能 •修改配置文件使其永远生效 第一种修改方法vi vi /etc/sysconfig/selinuc 或者 vi /etc/selinux/config修改: SELINUX=d ...

  6. 洛谷P3906 Hoof Paper, Scissor (记忆化搜索)

    这道题问的是石头剪刀布的的出题问题 首先不难看出这是个dp题 其次这道题的状态也很好确定,之前输赢与之后无关,确定三个状态:当前位置,当前手势,当前剩余次数,所以对于剪刀,要么出石头+1分用一次机会, ...

  7. 大厂是如何用DevCloud流水线实现自动化部署Web应用的?

    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站:devui.design Ng组件库:ng-devui(欢 ...

  8. linux离线安装docker + docker-compose

    1 准备阶段(docker) 1.1 卸载旧版本 如果电脑上已经存在docker,需要先卸载可能存在的旧版本: 1. 删除某软件,及其安装时自动安装的所有包 sudo apt-get autoremo ...

  9. PyQt(Python+Qt)学习随笔:QLineEdit行编辑器功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 QLineEdit部件是一个单行文本编辑器,支持撤消和重做. ...

  10. 第14.15节 爬虫实战1:使用Python和selenium实现csdn博文点赞

    写在前面:本文仅供参考学习,请勿用作它途,禁止转载! 在开始学爬虫时,学习了csdn博客专家(id:明天依旧可好 | 柯尊柏)<实战项目二:实现CSDN自动点赞>的文章,文章介绍了通过Py ...