(Ryan的Koa系列博客)4.依赖库:events概述
前言events库是node的内置库的内容,简单点说就是node的事件发布器。(订阅发布) 安装npm install events
依赖var EventEmitter = require('events').EventEmitter
node的事件机制大多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(一般称为触发器emitters)会周期性地发送(触发)被命名好的相关事件来调用被称为监听器的函数对象(一般称为触发器listeners)。
所有能发送(触发)事件的对象都是EventEmitter类的实例。这些对象都会暴露一个名为eventEmitter.on()的函数,并允许一个或者多个函数通过这个对象与一些有名字的事件关联到一起。事件名通常都是驼峰形式的字符串,但是,也可以用任何有效的js属性键作为事件名。 ??? 以下例子展示了一个只有单个监听器(listener)的 EventEmitter 实例。 eventEmitter.on() 方法用于注册监听器(listener),eventEmitter.emit() 方法用于触发事件。下面我们看一个例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
console.log('开始注册事件');
myEmitter.on('event',() => { console.log('发生了一个事件'); }); console.log('开始触发事件事件'); myEmitter.emit('event');
执行结果: 给监听器(listener)传入参数与this的使用方法在es5的语法下,eventEmitter.emit() 方法允许将任意参数集合传给监听器函数。 当一个普通的监听器函数被 EventEmitter 调用时,标准的 this 关键词会被设置指向监听器所附加的 EventEmitter。也就是说,this在监听器关联的事件中就代表EventEmitter对象。 我们来看一个例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event',function(a,b) {
console.log(a,b,this);
// Prints:
// a b MyEmitter {
// domain: null,
// _events: { event: [Function] },
// _eventsCount: 1,
// _maxListeners: undefined }
});
myEmitter.emit('event','a','b');
执行结果: 也可以使用 ES6 的箭头函数作为监听器。但是这样 this 关键词就不再指向 EventEmitter 实例,我们来看es6的例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event',(a,b) => {
console.log(a,this);
// Prints: a b {}
});
myEmitter.emit('event','b');
同步和异步EventListener 会按照监听器注册的顺序同步地调用所有监听器。 所以需要确保事件的正确排序且避免竞争条件或逻辑错误。 监听器函数可以使用 setImmediate() 或 process.nextTick() 方法切换为异步操作模式。 来我们看个例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event',b) => {
setImmediate(() => {
console.log('这个是异步发生的A');
});
console.log('这个是监听器的B');
// Prints:这个是监听器的B
//这个是异步发生的A
});
myEmitter.emit('event','b');
让事件使用一次之后被销毁使用 eventEmitter.on() 方法注册监听器时,监听器会在每次触发命名事件时都被调用。 const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
var m = 0;
myEmitter.on('event',() => {
console.log(++m);
});
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');
// 打印: 2
如果,不想让某个被注册的事件被调用多次,可以使用eventEmitter.once() 。使用 eventEmitter.once() 可以使被注册的事件,只能被监听器调用一次。 当事件被触发后,该事件的监听器会先被注销,然后再调用事件中的功能函数。我们来看下边的例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
var m = 0;
myEmitter.once('event',() => {
console.log(++m);
});
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');
// 忽略
报错事件When an error occurs within an EventEmitter instance,the typical action is for an ‘error’ event to be emitted. These are treated as special cases within Node.js. If an EventEmitter does not have at least one listener registered for the ‘error’ event,and an ‘error’ event is emitted,the error is thrown,a stack trace is printed,and the Node.js process exits. 当 EventEmitter 实例中发生错误时,典型做法应该是去注册一个 ‘error’ 事件,并触发这个事件。但是,这在 Node.js 中是个特例,或者说不应该被推荐的。因为,如果 EventEmitter 没有为 ‘error’ 事件注册至少一个监听器,则当 ‘error’ 事件触发时,会抛出错误,打印堆栈信息,然后退出 Node.js 进程。我们来看下边的一个例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.emit('error',new Error('whoops!'));
// Throws and crashes Node.js
如果又不想为事件注册监听器,又想防止 Node.js 进程崩溃,可以在 process 对象的 uncaughtException 事件上注册监听器。(node核心中提供了domain 模块,但是,该模块官方已经准备废弃了,我用过这个domain 模块,该模块的问题是过于占用内存,会影响整个系统的性能。不知道该模块的底层是什么样的结构,反正,是一个已经准备废弃的模块了,因此,也不需要去查看了),我们来看这样一个例子: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
process.on('uncaughtException',(err) => {
console.log('有错误');
});
myEmitter.emit('error',new Error('whoops!'));
// 打印: 有错误
当然,作为最佳实践,应该始终为 ‘error’ 事件注册监听器。 例子如下: const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('error',(err) => {
console.log('有错误');
});
myEmitter.emit('error',new Error('whoops!'));
// 打印: 有错误
后记本文只是依赖库events的概述。通过本文,我们知道了最主要的事件类EventEmitter,也知道了其他的事件类都是EventEmitter的实例,同时,我们还学习了注册、监听、触发、错误处理等多种事件的操作。node的异步事件是它的特殊之一,因此,学好node事件,是学好node的基础。本文篇幅有限,因此,关于EventEmitter类的深入解析将会在后续的文章中进行讲解。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |