加班加点额外一篇,防止呆滞(events{node.js})

279 阅读4分钟

大部分的node核心库的api都构建于惯用的设计架构之上(异步事件驱动架构),nice,完全听不懂就对了。

但是记住一点,一些特殊的对象,可以注册监听事件,也可以触发事件(监听器,触发器)。是通过两个方法实现的。

例如:有一个对象就是这些特殊对象之一:

SpecialObj.on('event', () => {
  console.log('触发事件');
});
SpecialObj.emit('event');

非常之明确,这个special的对象,先使用on方法注册了一个名字叫event的监听事件,然后传入一个函数让它可以在被触发的时候调用。 接下来使用emit方法触发它。如此之简单!

那么它是怎么实现的呢?确实是通过node的一个模块,名字叫做events(事件触发器)。之前所说的设计架构就是这个玩意。就是这个模式,记住这个模式与这个名字,ok,入门难关已经悄然过去。

再看看核心库的一些内容:例如,net.Server会在每次有新连接时触发事件,fs.ReadStream会在打开文件时触发事件,stream会在数据可读时触发事件。其实都是按照上面的模式去一次一次的触发的。

然后我们再看看官网的完整代码:

// 引入模块
const EventEmitter = require('events');
//创造一个类,继承这个模块的特性(事件触发器的特性,on和emit方法已经被继承)
class MyEmitter extends EventEmitter {}
//创造这个的实例,他现在已经拥有着无所不能的事件触发的能力了,奥里给。
const myEmitter = new MyEmitter();

//干些它该干的事情
myEmitter.on('event', () => {
  console.log('触发事件');
});
myEmitter.emit('event');
  • 监听器函数内this指向

监听器(喂,我之前介绍过监听器)内传的函数,是可以收到this的,默认也是指向注册监听器的实例,举个例子:

myEmitter.on('event', function() {
  console.log(this); // this === myEmitter
});

不要滥用箭头函数,在使用this的函数内最好还是选择使用es5的模式。在这使用箭头函数将会无法寻找上一级的this上下文执行环境。具体的表现还需要去实验一下。详情参考阮一峰es6

  • 监听器函数内异步操作

监听器的注册顺序,也就是从上往下书写myEmitter.on的顺序决定了触发时调用的顺序。

这样可以确保事件的正确排序,并有助于避免各个监听器竞争导致逻辑错误。当然,监听器函数可以使用 setImmediate() 和 process.nextTick()使其脱离这个同步的顺序:

const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('异步地发生');
  });
});
myEmitter.emit('event', 'a', 'b');
  • 我的监听器只需要触发一次!

你应该清楚,上面使用on方法去注册的监听器,是无限触发的,意味着你只要使用emit去触发相应的事件,那么就会有回应。某些情况我们是需要一些只触发一次的事件,这个改如何去实现呢?很幸运,events模块给了我们解决方案:

eventEmitter.on() => eventEmitter.once() 
  • 监听特殊事件error防止node崩溃

如果eventEmitter的实例出错了,也没有为'error'事件注册监听器,则当'error'事件触发时(强行触发,没有也触发),会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。

我们肯定是不希望随随便便我的后台就蹦了,这不是搞笑吗,出错就蹦出错就蹦,真就小霸王了。

我们可以为止注册error监听器,这样我们就可以处理error的事件了,他就不会随便蹦了。最好在error的监听器内设置一些对错误处理的逻辑,可以使得我们更快的查找到问题的所在并修改它。

当然,有些关键的实例,它的存在就是核心,它触发错误,整个系统就该崩溃,不然就会发生更大的问题。例如发红包服务器,它红包这个监听器疯了乱发红包,最好还是整个服务器蹦了,不然发出去几百万,程序员直接牢底坐穿。

所以我们需要在其发生错误的时候,捕捉信息,并且,让他蹦。

const myEmitter = new MyEmitter();
myEmitter.on(EventEmitter.errorMonitor, (err) => {
  MyMonitoringTool.log(err);
});
myEmitter.emit('error', new Error('错误'));
// 仍然抛出错误并使 Node.js 崩溃。

借助EventEmitter.errorMonitor实现它。

  • EventEmitter类

他是怎么来的? const EventEmitter = require('events'); 这个类很坏,他在内部直接偷偷搞了一些emit,对就是触发器。 之前每一个实例都是需要继承它来实现的,这就导致了,大家都是有一个爸爸,这个爸爸有个规定,谁自己添加了一个新的监听器啊,就会触发自己的一个特殊的事件“newListener”,谁移走了个监听器,就会触发另外一个特殊事件“removeListener”。所以你可以监听这两事件,做一些你想做的事情。

                                                                                                            ## 未完待续……