文章目录

  • 一、Node.js事件循环
  • 二、事件驱动程序
  • 三、事件触发器
    • 1、EventEmitter类
    • 2、事件触发器的方法
      • (1)EventEmitter类的on方法
      • (2)EventEmitter类的once方法
      • (3)使用removeListener方法取消事件处理函数
      • (4)自定义事件并将其触发
  • 四、错误事件

一、Node.js事件循环

Node.js是单进程单线程应用程序,但是因为V8引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。
       Node.js几乎每一个API都是支持回调函数的。
       Node.js基本上所有的事件机制都是用设计模式中观察者模式实现
       Node.js单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数

二、事件驱动程序

Node.js使用事件驱动模型,当Web server接受到请求,就把它关闭然后进行处理,然后去服务下一个web请求。当这个请求完成后,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
       这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也称为非阻塞式IO或者事件驱动IO)
       在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
注意:线程是整个程序的最小单位,即一个程序就是一个进程,一个进程里至少要运行一个线程。
       在Node.js的事件机制中主要有三类角色:事件(Event)、事件发射器(EventEmitter)、事件监听器(EventListener)
       Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件。例如:

//引入events模块
var events = require('events');
//创建eventEmitter对象
var eventEmitter = new events.EventEmitter();
//绑定事件及事件的处理程序
eventEmitter.on('eventName',eventHandler);
//触发事件
eventEmitter.emit('eventName');

三、事件触发器

Node.js 的大部分核心 API 都是围绕惯用的异步事件驱动架构构建的,在该架构中,某些类型的对象(称为"触发器")触发命名事件,使 Function 对象(“监听器”)被调用。
       EventEmitter类:事件发射器,也叫事件触发器,所有可能触发事件的对象都是一个集成了EventEmitter类的子类的实例对象,这些对象暴露了 eventEmitter.on() 函数,允许将一个或多个函数绑定到对象触发的命名事件。 通常,事件名称是驼峰式字符串,但也可以使用任何有效的 JavaScript 属性键。
       当 EventEmitter 对象触发事件时,所有绑定到该特定事件的函数都会被同步地调用。 被调用的监听器返回的任何值都将被忽略和丢弃。
       EventEmitter 按照注册的顺序同步地调用所有监听器。 这确保了事件的正确排序,并有助于避免竞争条件和逻辑错误。 在适当的时候,监听器函数可以使用 setImmediate() 或 process.nextTick() 方法切换到异步的操作模式。

1、EventEmitter类

EventEmitter 类由 events 模块定义和暴露:

const EventEmitter = require('events');

所有的 EventEmitter,当添加新的监听器时触发事件 ‘newListener’,当删除现有的监听器时触发事件 ‘removeListener’。

2、事件触发器的方法

在Node.js中,为EventEmitter类定义了许多方法,所有与对象的事件处理函数的绑定及解除相关的处理均依靠这些方法的调用来执行。
常用方法:(event:代表事件名,listener:代表事件处理函数)

方法名与参数 描述
addListener(event,listener) 事件监听函数,emitter.on(eventName, listener) 的别名。
on(event, listener) 对指定对象绑定事件处理函数(addListener方法的别名)
once(event, listener) 对指定对象指定只执行一次的事件处理函数
removeListener(event, listener) 删除事件
setMaxListeners(n) 指定对象处理函数的最大数量,n为正数值,代表最大的可指定事件处理函数的数量
listeners(event) 获取指定对象的所有事件处理函数
emit(event, [arg1], [arg2], […]) 手动触发指定事件
newListener(event,Listener) 添加新的监听器

(1)EventEmitter类的on方法

emitter.on(eventName, listener);

eventName < string > | < symbol > 事件的名称。
listener < Function > 回调函数
返回: < EventEmitter >
       将 listener 函数添加到名为 eventName 的事件的监听器数组的末尾。 不检查是否已添加 listener。 多次调用传入相同的 eventName 和 listener 组合将导致多次添加和调用 listener。默认情况下,事件监听器按添加顺序调用。

例1:当服务器接收到客户端请求时,在控制台窗口中输出客户端请求的目标地址(URL地址),并使用响应对象的end方法立即结束响应。

const http = require('http');
//创建服务器对象
let server = http.createServer();
//给服务器对象绑定事件request
server.on('request',function (req,res){//输出请求对象的地址console.log('请求地址:',req.url);//服务器关闭和客户端的连接,并发送响应信息res.end('hello world');
})
//服务器启动监听
server.listen(8089,'127.0.0.1');



例2:也可以通过多个on方法的执行来对同一个事件绑定多个事件处理函数。

var http = require("http");
//创建服务器对象
var server = http.createServer();
//给服务器对象绑定多个事件处理函数
server.on('request',function(req,res){console.log('接收到客户端请求')
})
server.on("request",function(req,res){console.log('处理客户端请求')console.log(req.url);res.end('hello');
})
server.on('request',function(req,res){console.log('发送响应完毕')
})
//服务器启动监听
server.listen(1337,"127.0.0.1");


(2)EventEmitter类的once方法

emitter.once(eventName, listener);

eventName < string > | < symbol > 事件的名称。
listener < Function > 回调函数
返回: < EventEmitter >
       为名为 eventName 的事件添加单次的 listener 函数。 下次触发 eventName 时,将移除此监听器,然后再调用。
       once方法与on方法类似,作用均为对指定事件绑定事件处理函数,区别在于,当事件处理函数执行一次后立即被结束,即该事件处理函数只会被执行一次。once方法所用参数与on方法所用参数相同。
       默认情况下,事件监听器按添加顺序调用。

var http = require("http");
//创建服务器对象
var server = http.createServer();
//给服务器对象绑定多个事件处理函数
server.once('request',function(req,res){console.log('接收到客户端请求')
})
server.on("request",function(req,res){console.log('处理客户端请求')console.log(req.url);res.end();
})
server.once('request',function(req,res){console.log('发送响应完毕')
})
//服务器启动监听server.listen(80,function(){console.log('http://127.0.0.1')
});

由结果可以看出,once方法绑定的事件处理函数只执行了一次。

(3)使用removeListener方法取消事件处理函数

emitter.removeListener(eventName, listener);

eventName < string > | < symbol >
listener < Function >
返回:< EventEmitter >
       从名为 eventName 的事件的监听器数组中移除指定的 listener。
       removeListener() 最多从监听器数组中删除一个监听器实例。 如果任何单个监听器已多次添加到指定 eventName 的监听器数组中,则必须多次调用 removeListener() 以删除每个实例。
       一旦事件被触发,则所有在触发时绑定到它的监听器都会被依次调用。这意味着在触发之后和最后一个监听器完成执行之前的任何 removeListener()或removeAllListeners()调用都不会从正在进行的 emit() 中删除它们。后续事件按预期运行。
举例如下:

const event = require('events');
//创建EventEmitter的实例对象
const myEmitter = new event.EventEmitter();
const f1 = function (){console.log('f1的结果为1');myEmitter.removeListener('conduct',f2)
};
const f2 = function (){console.log('f2的结果为2')
};
myEmitter.on('conduct',f1);
myEmitter.on('conduct',f2);
//手动触发事件
myEmitter.emit('conduct');
//结果为1  2,可见,虽然我们在f1里删除了f2,但它依旧被调用了
myEmitter.emit('conduct');
//结果为1,此时f2才被删除

当单个函数被多次添加为单个事件的句柄时(如下例所示),则 removeListener() 将删除最近添加的实例。如:

const event = require('events');
const myEmitter = new event.EventEmitter();
function f1(){console.log('茕茕孑立,形影相吊');
}
function f2(){console.log('北风卷地白草折,胡天八月即飞雪')
}
myEmitter.on('bear6',f1);
myEmitter.on('bear6',f2);
myEmitter.on('bear6',f1);
myEmitter.on('bear6',f2);
myEmitter.removeListener('bear6',f2);
myEmitter.emit('bear6');
//我们给myEmitter绑定了多个名字相同的事件,removeListener()删除最近添加的实例。

(4)自定义事件并将其触发

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

eventName < string > | < symbol >
…args < any > 自定义参数
返回: < boolean >
       按注册顺序同步地调用为名为 eventName 的事件注册的每个监听器,并将提供的参数传给每个监听器。
       如果事件有监听器,则返回 true,否则返回 false。

const event = require('events');
const myEmitter = new event.EventEmitter();
myEmitter.on('bear6',function first() {console.log('这是第一个监听器');
});
myEmitter.on('bear6',function second(arg1,arg2){console.log(`这是第二个监听器${arg1},${arg2}`);
});
myEmitter.on('bear6',function third(...args){console.log(`这是第三个监听器${args}`);
});
myEmitter.emit('bear6',1,2,3,4,5);

结果如下:

四、错误事件

当 EventEmitter 实例中发生错误时,典型的操作是触发 ‘error’ 事件。 这些在 Node.js 中被视为特殊情况。
       如果 EventEmitter 没有为 ‘error’ 事件注册至少一个监听器,并且触发 ‘error’ 事件,则会抛出错误,打印堆栈跟踪,然后退出 Node.js 进程。
       为了防止 Node.js 进程崩溃,应始终为 ‘error’ 事件添加监听器。

const event = require('events');
const myEmitter = new event.EventEmitter();
myEmitter.on('error',function (err){console.error('this is error')
});
myEmitter.emit('error');

事件处理过程中抛出的错误,可以使用try…catch捕获。

let EventEmitter = require('events').EventEmitter;
let emitter = new EventEmitter();emitter.on('beep',function(){console.log('beep');
});
emitter.on('beep',function(){throw Error('oops!');
});
emitter.on('beep',function(){console.log('beep again');
});console.log('before emit');
try{emitter.emit('beep');
}catch(err){console.error('caught while emitting:',err.message);
}
console.log('after emit');

从结果中可以看出,beep again并没有被打印,因为经过try…catch…后,catch接收到了错误并抛出,beep事件错误后面的监听器不会被启动。

Node.js学习五(事件)相关推荐

  1. 《写给PHP开发者的Node.js学习指南》一2.2 预定义的PHP变量

    本节书摘来自异步社区<写给PHP开发者的Node.js学习指南>一书中的第2章,第2.1节,作者[美]Daniel Howard,更多章节内容可以访问云栖社区"异步社区" ...

  2. node.js学习笔记

    # node.js学习笔记标签(空格分隔): node.js---## 一 内置模块学习 ### 1. http 模块 ``` //1 导入http模块 const http =require('ht ...

  3. Node.js学习笔记8

    Node.js学习笔记8 HTTP服务器与客户端 Node.js的http模块,封装了一个高效的HTTP服务器和一个简易的HTTP客户端 http.server是一个基于事件的HTTP服务器,核心由N ...

  4. node.js学习笔记5——核心模块1

    node.js学习笔记5--核心模块1 Node.js核心模块主要内容包括:(1)全局对象 (2)常用工具 (3)事件机制 (4)文件系统访问 (5)HTTP服务器与客户端 一: 全局对象 Node. ...

  5. node.js学习总结:node.js的内置模块,模块化,npm与包 express,前后端身份认证 JWT认证机制

    node.js学习总结 什么是node.js node.js的内置模块 fs系统模块 path路径模块 http模块 模块化 npm与包 express express路由 express+mysql ...

  6. 千锋Node.js学习笔记

    千锋Node.js学习笔记 文章目录 千锋Node.js学习笔记 写在前面 1. 认识Node.js 2. NVM 3. NPM 4. NRM 5. NPX 6. 模块/包与CommonJS 7. 常 ...

  7. node.js学习笔记14—微型社交网站

    node.js学习笔记14-微型社交网站 1.功能分析 微博是以用户为中心,因此需要有注册和登录功能. 微博最核心的功能是信息的发表,这个功能包括许多方面,包括:数据库访问,前端显示等. 一个完整的微 ...

  8. 如何正确使用Node.js中的事件

    by Usama Ashraf 通过Usama Ashraf 如何正确使用Node.js中的事件 (How to use events in Node.js the right way) Before ...

  9. node.js 学习笔记(二)模板引擎和C/S渲染

    node.js 学习笔记(二)模板引擎和C/S渲染 文章目录 node.js 学习笔记(二)模板引擎和C/S渲染 一.初步实现Apache功能 1.1 使用模板引擎 1.2 在 node 中使用模板引 ...

最新文章

  1. Infineon第九届汽车电子开发者大会宣传视频
  2. 使用Ubuntu挂载NTFS格式分区
  3. 计算器初步添加消息响应
  4. 数据中心网络性能:新应用下的新需求
  5. JavaScript学习笔记系列2:Dom操作(一)
  6. Django(part53)--404模板文件
  7. Description Resource Path Location Type Java compiler level does not match the version of the insta
  8. 初学JAVA随记——代码练习(二元一次方程)
  9. hibernate教程_Hibernate教程
  10. 计算机快捷键换行,excel换行快捷键 excel中自动换行的快捷键是什么
  11. 服务器搬迁需要注意的几个地方
  12. Android 如何屏蔽返回键和Home键
  13. hping3对某网站发起ddos攻击
  14. 在XP IIS5.1手工安装PHP 5.2.11
  15. word怎么删除参考文献的横线_word2016怎么去掉引用参考文献的横线?
  16. PS按照图片大小调整画布大小
  17. hyperopt/hyperas
  18. (附源码)计算机毕业设计SSM大学生互动交流论坛
  19. linux zip压缩排除目录,Linux系统zip压缩命令详细参数,附文件排除选项的正确用法...
  20. css零到一中级教程025:CSS 特异性

热门文章

  1. xen(四)xen配置文件
  2. 故障转移集群无法连接到节点_《使命召唤:黑色行动4》联网出现故障 玩家无法连接游戏...
  3. 程序员旅游之吐糟途牛——第一天
  4. 成立十年之后,集团化的途牛将业务分拆为旅游度假和金融科技
  5. 批量将MP4 转换为 MP3
  6. 【网络安全】考试试卷十二
  7. arcgis界址点编号工具开发原理
  8. 扩展JQuery中的slideToggle()方法
  9. mysql支持pivot
  10. Linux bpf 3.2、BPF and XDP Reference Guide