Node events(事件)的使用

Node events文档地址:http://nodejs.cn/api/events.html

1 背景

今天使用AWS IOT时发现一个问题,当server作为节点接入AWS IOT网络对设备发送命令,发现等待响应流程有点问题。
(1)所有接受消息的行为都是在一个回调函数中执行的,意味着来自不同设备的响应都只会触发这个回调。
(2)在同级文件中定义了一个发送命令的函数,该函数要发送命令并等待设备响应再返回结果。
这两个行为就导致了一个问题,当调用发送函数时,发送函数push出消息,这里就需要等待设备发送响应,但接收函数并不在该发送函数内部,正常流程就直接return了。这里就需要一种方式让发送函数等待并接受到响应后再return。
这里发现node有一个非常方便的方案(event)解决这个问题。

2 events

大多数 Node.js 核心 API 都采用惯用的异步事件驱动架构,其中某些类型的对象(触发器)会周期性地触发命名事件来调用函数对象(监听器)。
所有能触发事件的对象都是 EventEmitter 类的实例。 这些对象开放了一个 eventEmitter.on() 函数,允许将一个或多个函数绑定到会被对象触发的命名事件上。 事件名称通常是驼峰式的字符串,但也可以使用任何有效的 JavaScript 属性名。

结合code一些概念进行说明

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

myEmitter.on('event', () => {
  console.log('触发了一个事件!');
});
myEmitter.emit('event');

上诉代码:一个绑定了一个监听器的 EventEmitter 实例。 eventEmitter.on() 方法用于注册监听器,eventEmitter.emit() 方法用于触发事件。
下面是我对几个概念的理解。
事件:Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
触发器:用于触发命名事件。
监听器:将命名事件与特定函数对象绑定到一起,当事件被触发时就会调用该函数,一直等待事件触发(监听)。

3 sample

3.1 Event 事件触发效果

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

let Say = function(callback){
    console.info("I'll say something when I'm ready")
    myEmitter.on('message', (data) => {//注册了一个监听器并绑定到message这个事件上
        console.log(data);
        return callback(null, "yeah,I've said it.");
    });
}

Say(function(err, data){//调用say函数,say函数执行,等待message事件触发
    console.info(data)
});

setTimeout(function(){
    console.info("I'm ready");
    myEmitter.emit('message', 'helloworld');//触发message事件,say函数监听内容继续执行
},3000);

3.2 只触发一次

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');

使用 eventEmitter.once() 方法时可以注册一个对于特定事件最多被调用一次的监听器。 当事件被触发时,监听器会被注销。
即该监听器只会触发一次。

3.3 eventEmitter的异常处理

当 EventEmitter 实例中发生错误时,会触发一个 ‘error’ 事件。 这在 Node.js 中是特殊情况。
如果没有注册error事件,则node 会直接挂掉。所以我们应该为EventEmitter 注册error事件。

const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
  console.error('有错误');
});
myEmitter.emit('error', new Error('whoops!'));

3.4 EventEmitter 类

EventEmitter 类由 events 模块定义和开放的:
const EventEmitter = require(‘events’);
当新的监听器被添加时,所有的 EventEmitter 会触发 ‘newListener’ 事件;当移除已存在的监听器时,则触发 ‘removeListener’。

3.4.1 newListener事件

当绑定新触发器时触发newListener事件

const myEmitter = new MyEmitter();
// 只处理一次,所以不会无限循环
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // 在开头插入一个新的监听器
    myEmitter.on('event', () => {
      console.log('B');
    });
  }
});
myEmitter.on('event', () => {
  console.log('A');
});
myEmitter.emit('event');

3.4.2 removeListener事件

‘removeListener’ 事件在 listener 被移除后触发。

3.5 取消监听器

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
let eventFunction = function(){
    console.log(++m);
}
myEmitter.on('event',eventFunction);
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');
// 打印: 2
myEmitter.removeListener('event', eventFunction);
myEmitter.emit('event');
//取消监听器 不打印 

3.6 最大监听器限制

每个事件node监听器被默认限制为10。注意是每个事件 ,不同事件时可以超过10的。

emitter.getMaxListeners()获取当前最大监听器限制
emitter.setMaxListeners(n)设定当前最大监听器限制

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

4 用于解决上述背景中提出的问题的code

device.on("message", function(topic, payload){//接收来自设备的消息
    myEmitter.emit(topic, payload);//接受到 对应ID 的消息就触发发送函数中相应的函数返回结果
})

var sendMessage  = function(topic,data, callback){
    device.push(topic, data);
    myEmitter.once(topic, (payload) => {
       return callback(null, payload);
    });
}

猜你喜欢

转载自blog.csdn.net/m0_37263637/article/details/80944845