node.js 事件 和 EventEmitter类

在学习stream的时候,看到文档中有这么一句:所有的 Stream 对象都是 EventEmitter 的实例,常用的事件有 data,end 等等。

当时就在想为什么要说是 EventEmitter 的实例这句话呢?还有事件是什么?继续看下去就明白了。

EventEmitter 类

events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。

上面这句话就可以看出来在node.js中所有的事件操作都封装在 EventEmitter 中,那么具体是怎么添加事件和触发事件呢?

下面看一个实例:

const eventEmitter = require('events').EventEmitter;

// 创建EventEmitter实例
let event = new EventEmitter();

// 注册a_event事件,第二个参数是一个函数,在这里叫做监听器
event.on('a_event', () => {
    console.log('触发 a_event 事件');
});

setTimeout(() => {
    // 一秒后触发a_event事件
    event.emit('a_event');
}, 1000)


out:
	触发 a_event 事件

上面这段代码的原理是 event 对象注册了事件 a_event 的一个监听器,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 a_event,此时会调用 a_event 的监听器。

原来可以通过EventEmitter类自定义一个事件并且手动触发它。

EventEmitter 的简单用法

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。

对于每个事件,EventEmitter 支持 若干个事件监听器。当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

let events = require('events');

// 创建EventEmitter实例
let emitter = new events.EventEmitter(); 

// 注册第一个事件监听器
emitter.on('a_event', (arg1, arg2) => { 
    console.log('listener1', arg1, arg2); 
});

// 注册第二个事件监听器
emitter.on('a_event', (arg1, arg2) => { 
    console.log('listener2', arg1, arg2); 
});

// 触发事件
emitter.emit('a_event', 'arg1 参数', 'arg2 参数'); 


out:
	listener1 arg1 参数 arg2 参数
	listener2 arg1 参数 arg2 参数

EventEmitter 的常用方法

  • on(event, listener)

    // 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
    server.on('connection', function (stream) {
      console.log('someone connected!');
    });
    
  • once(event, listener)

    // 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
    server.once('connection', function (stream) {
      console.log('Ah, we have our first user!');
    });
    
  • emit(event, [arg1], [arg2], […])

    // 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
    emitter.emit('a_event', 'arg1 参数', 'arg2 参数'); 
    
  • listeners(event)

    // 返回指定事件的监听器数组。
    emitter.listeners('a_event')
    // 返回指定事件的监听器数量。
    emitter.listeners('a_event').length
    
  • addListener(event, listener)

    // 为指定事件添加一个监听器到监听器数组的尾部。
    
  • removeListener(event, listener)

    
    // 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。
    
    // 它接受两个参数,第一个是事件名称,第二个是回调函数名称。
    
    var callback = function(stream) {
      console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback);
    
  • removeAllListeners([event])

    // 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
    
  • setMaxListeners(n)

    // 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。			
    

EventEmitter 的事件

  • newListener

    // 该事件在添加新监听器时被触发。			
    
  • newListener

    // 从指定监听器数组中删除一个监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引。			
    

EventEmitter 的 error 事件

EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,我们在遇到 异常的时候通常会触发 error 事件。

当 error 被触发时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并输出错误信息。

我们一般要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。

看两个例子:

  1. 不为 error 事件设置监听器

    // 创建EventEmitter实例
    let emitter = new events.EventEmitter(); 
    
    // 直接触发 error 事件
    emitter.emit('error'); 
    
    // 程序会在上面终止,不会打印 end
    console.log('end');
    
    
    out:
    	throw err; // Unhandled 'error' event
    	...
    
  2. 为 error 事件设置监听器

    // 创建EventEmitter实例
    let emitter = new events.EventEmitter(); 
    
    // 为 error 设置监听器
    emitter.on('error', () => {
        console.error('事件异常');
    });
    
    // 直接触发 error 事件
    emitter.emit('error'); 
    
    // 程序不会在上面终止,会打印 end
    console.log('end');
    
    
    out:
    	事件异常
    	end
    

继承 EventEmitter

大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

到这来终于明白了为什么说所有的 Stream 对象都是 EventEmitter 的实例,因为 stream 对象继承了EventEmitter类,这样它就可以使用EventEmitter类的事件功能(EventEmitter类方法、属性、事件等),而不需要自己再去定义这些功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值