从发布订阅模式入手读懂Node.js的EventEmitter源码 (2)

image-20200323170909507

构造函数很简单,就一行代码,主要逻辑都在EventEmitter.init里面:

image-20200323171123339

EventEmitter.init里面也是做了一些初始化的工作,this._events跟我们自己写的this.events功能是一样的,用来存储订阅的事件。核心代码我在图上用箭头标出来了。这里需要注意一点,如果一个类型的事件只有一个订阅,this._events就直接是那个函数了,而不是一个数组,在源码里面我们会多次看到对这个进行判断,这样写是为了提高性能。

订阅事件

代码传送门:

EventEmitter订阅事件的API是on和addListener,从源码中我们可以看出这两个方法是完全一样的:

image-20200323171656342

这两个方法都是调用了_addListener,这个方法对参数进行了判断和错误处理,核心代码仍然是往this._events里面添加事件:

image-20200323172045655

发布事件

代码传送门:

EventEmitter发布事件的API是emit,这个API里面会对"error"类型的事件进行特殊处理,也就是抛出错误:

image-20200323172657760

如果不是错误类型的事件,就把订阅的回调事件拿出来执行:

image-20200323172822170

取消订阅

代码传送门:

EventEmitter里面取消订阅的API是removeListener和off,这两个是完全一样的。EventEmitter的取消订阅API不仅仅会删除对应的订阅,在删除后还会emit一个removeListener事件来通知外界。这里也会对this._events里面对应的type进行判断,如果只有一个,也就是说这个type的类型是function,会直接删除这个键,如果有多个订阅,就会找出这个订阅,然后删掉他。如果所有订阅都删完了,就直接将this._events置空:

image-20200323174111868

观察者模式

这里再提一个很相似的设计模式:观察者模式,有些文章认为他和发布订阅模式是一样的,有些认为他们是有区别的。笔者认为他更像一个低配版的发布订阅模式,我们来实现一个看看:

class Subject { constructor() { // 一个数组存放所有的订阅者 // 每个消息对应一个数组,数组结构如下 // [ // { // observer: obj, // action: () => {} // } // ] this.observers = []; } addObserver(observer, action) { // 将观察者和回调放入数组 this.observers.push({observer, action}); } notify(...args) { // 执行每个观察者的回调 this.observers.forEach(item => { const {observer, action} = item; action.call(observer, ...args); }) } } const subject = new Subject(); // 添加一个观察者 subject.addObserver({name: 'John'}, function(msg){ console.log(this.name, 'got message: ', msg); }) // 再添加一个观察者 subject.addObserver({name: 'Joe'}, function(msg) { console.log(this.name, 'got message: ', msg); }) // 通知所有观察者 subject.notify('tomorrow is Sunday');

上述代码的输出是:

image-20200323205318223

通过这个输出可以看出一旦调了通知的方法notify,所有观察者都会收到通知,而且会收到同样的信息。而发布订阅模式还可以自定义需要接受的通知,所以说观察者模式是低配版的发布订阅模式。

总结

本文讲解了发布订阅模式的原理,并自己实现了一个简单的发布订阅模式。在了解了原理后,还去读了Node.js的EventEmitter模块的源码,进一步学习了生产环境的发布订阅模式的写法。总结下来发布订阅模式有以下特点:

解决了“回调地狱”

将多个模块进行了解耦,自己执行时,不需要知道另一个模块的存在,只需要关心发布出来的事件就行

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssfff.html