大家好,今天我们介绍一款JS的事件总结组件,那么什么是事件总线、以及它能够解决哪些问题?比如有这么一个场景,当我们在项目开发时需要进行跨页面的数据传输、页面状态通知等。如订购场景、订阅场景、页面事件更新场景等,需要实现事件(流)、数据订阅、分发场景可以称之为事件总线。它能够解决复杂项目模块与模块之间的耦合度、以及降低跨组件数据传输的复杂度。那么问题来了,我们怎么去构建一套完整且实用的前端JS事件总结组件,继续往下看跟随逐步来完成组件的开发过程。
在封装组件前我们需要考虑哪些问题呢?
- 如何确保组件在使用过程中的单一性(即JS单例的实现)?
- 怎么去设计组件订阅、分发(可以被哪些组件接收)?
- 是否可以解决事件分发丢失的现象?
如果这些问题在研发过程都能得到合理的解决,那么该组件在项目应用中也会很好的呈现;下面我们将逐一分析和输出原理和示例;
定义eventBus组件并实现单例模式(组件实例的单一性)
为什么要确保组件单一性?因为对于高频使用的组件来说,它在多个地方被多次调用,如果每次都去创建一个新的,那么在内存中就会出现多个相同功能的实现指向对应的指针,在大量事件、数据处理或高并发测试时极易导致内存溢出现象(也就是我们常说的雪崩现象);
这里我们使用js的Class包装类方法进行封装,class类的具体使用与好处可参考我前面写的《ES6中的Class方法与早期JavaScript方法有哪些本质区别》和《JS设计模式之单例原型》文章内容。
class EventBus {
static instance = null ?? new EventBus(); //这里赋值默认值,目的getInstance()显示的返回类型
constructor() {
if (EventBus.instance) {
return EventBus.instance;
}
EventBus.instance = this;
}
static getInstance() {
if (!EventBus.instance) {
EventBus.instance = new EventBus();
}
return EventBus.instance;
}
//这里实现你的逻辑
}
订阅事件和数据流(消费者)
订阅事件用于处理异步数据事件,其主要基于发布-订阅模式(pub/sub)接收端处理,以route作为订阅维度存储到全局_eventMap hash列表中;当接收端回调receive函数后,可以根据返回的action参数来区分不同的业务;有时候当在消费者处理完业务逻辑或需要更新状态给生产者时,此时就可以通过call回调函数来返回数据,call函数由生产者定义并传入;(如下是event bus消费者-订阅实现逻辑)
/**
* 订阅事件
* @param route @{Pages} 路由对象
* @param receive 订阅事件接收回调事件,当接收事件时会传回3个参数:
* action:用于区分业务事件标识
* params:接收事件数据参数
* call:回调事件处理,接收端可以通过此回调将数据返还给发送端
*/
subscribe(route = '', receive = function(action = '', params = {
}, call = function(params) {
}) {
console.log(`接收到来自${
route}的${
action}事件参数:`, params);
}) {
//校验订阅页面或组件的标签、路由是否有效
//因为后面的事件是根据route来分发的,所以必须保证其不为空
if (route === undefined || route === null || route === '') {