面试官在对 Vue 或者 React 进行深入询问的时候一定会问到组件间通讯。除去基本的父子组件和中大型项目所用到的,就剩下Event Bus
了。
这时候面试官问你:老弟你有没有想过自己实现一个Event Bus
?
提要
安卓中的Event Bus
、NodeJS 中的Event
模块()等等均需要用到Event Bus
。所以理解其中原理也是一个必不可少的过程和要求。
具体代码我们可以参考 Node 中的 Event API,它就是发布订阅模式的典型应用
Event Bus
这东西如上所述,是咱们在小型项目中用来通知下兄弟组件执行一些方法的。那么咱们具体应该如何实现呢?
如果希望了解EventBus
作为中间件通信可以点击这里,《Vue自定义组件事件传递:EventBus部分》。
如果希望了解 Vue 父子组件间通讯和组件内通讯则可以看我相关的博客 《Vue中的$emit、$on和v-on》)
但是既然咱们开了这个口还是总结一下叭:
EventBus
的作用就是作为一个中间件,是链接两个组件的一座桥梁。
- 发送方通过
EventBusName.$emit('eventName', data)
将数据和事件名传递给EventBus
- 接收方则通过
EventBusName.$on('eventName', methods)
对数据进行处理
实现
通过刚才的大致介绍我们得知:EventBus
可以理解为一个发布订阅模式的典型应用,所以说如果让我们实现,那么就可以理解为实现一个双向的发布订阅器。
初版
初始化
我们通过 ES6 的Class
关键字对Event
进行初始化。包括Event
的事件清单和监听者上限。
我们选择了Map
作为储存事件的结构,因为作为键值对的存储方式Map
比一般对象更加适合,操作更简洁
1 | class EventEmeitter { |
监听与触发
触发监听函数我们可以用apply
和call
两种方法。Node 中当参数小于 3 个时使用call
,否则用apply
。
1 |
|
如果有多个监听者呢
1 | // 重复监听同一个事件名 |
升级改造
监听器、触发器升级
我们的addListener
实现方法还不够健全。在绑定第一个监听者之后就无法对后续监听者进行绑定。故我们需要将所有监听者放入一个数组中
1 |
|
如此即可触发多个监听者的函数了
1 | // 监听同一个事件名 |
移除监听
我们通过removeListener
函数移除监听函数,但无法移除匿名函数
1 | EventEmeitter.prototype.removeListener = function(type, fn) { |
仍有问题
我们已经基本完成了Event
最重要的几个方法,也完成了升级改造,可以说一个Event
的骨架是被我们开发出来了,但是它仍然有不足和需要补充的地方.
- 鲁棒性不足: 我们没有对参数进行充分的判断,没有完善的报错机制.
- 模拟不够充分: 除了
removeAllListeners
这些方法没有实现以外,例如监听时间后会触发newListener
事件,我们也没有实现,另外最开始的监听者上限我们也没有利用到.
当然,这在面试中现场写一个Event已经是很够意思了,主要是体现出来对发布-订阅模式的理解,以及针对多个监听状况下的处理,不可能现场撸几百行写一个完整Event.
索性Event库帮我们实现了完整的特性,整个代码量有300多行,很适合阅读,你可以花十分钟的时间通读一下,见识一下完整的Event实现.
原文
作者:寻找海蓝96
链接:https://juejin.im/post/5ac2fb886fb9a028b86e328c
总结
Event Bus
的实现其实和 Vue 实现双向绑定的方式一样,把这个拿出来其实我是有炒冷饭的嫌疑的。不过作为一个冷门的知识点拿出来单说其实也不错,至少不会被一下问懵。今后如果能想起来的话我会着重复习并总结一下 JS 中常用的设计模式以及 OOP 的实现方式等,那么,后会有期江湖见!