首页 > 其他分享 >前端面试题:如何实现事件总线 Event Bus

前端面试题:如何实现事件总线 Event Bus

时间:2023-02-13 17:01:12浏览次数:56  
标签:面试题 const string Bus events type Event fn isOnce

前端面试题:如何实现事件总线 Event Bus

介绍

通常作为多个模块间的通信机制,相当于一个事件管理中心,一个模块发送消息,其它模块接受消息,就达到了通信的作用。

原理

本质上是采用了发布-订阅的设计模式,比如多个模块 A、B、C 订阅了一个事件 EventX,然后某一个模块 X 在事件总线发布了这个事件,那么事件总线会负责通知所有订阅者 A、B、C,它们都能收到这个通知消息,同时还可以传递参数。

分析

如何使用 JavaScript 来实现一个简单版本的 Event Bus

  1. 创建一个类
  2. 又一个事件池,用来保存发布的事件
  3. 有一个发布的方法,将事件发布
  4. 有一个订阅的监听机制,来触发事件的回调
  5. 有取消订阅的机制
  6. 有只订阅一次的机制

实现

创建一个类

class EventBus {}

创建一个事件池

class EventBus {
  private events: {
    [key: string]: Array<{fn: Function, isOnce: boolean}>
  }

  constructor() {
    this.events = {}
  }
}

发布事件

  1. 第一个参数是事件的KEY值, 剩余是接收事件的参数
  2. 在处理事件池中的监听时,将只监听一次的事件去除
class EventBus {
  private events: {
    [key: string]: Array<{fn: Function, isOnce: boolean}>
  }

  constructor() {
    this.events = {}
  }
  emit(type: string, ...args: any[]) {
    const fnList = this.events[type]
    if (fnList == null) return
    this.events[type] = fnList.filter(item => {
      const {fn, isOnce} = item
      fn(...args)
      return !isOnce
    })
  }
}

订阅事件

class EventBus {
  private events: {
    [key: string]: Array<{fn: Function, isOnce: boolean}>
  }

  constructor() {
    this.events = {}
  }
  on(type: string, fn: Function, isOnce:boolean=false){
    const events = this.events
    if (events[type] == null) {
      this.events[type] = []
    }
    this.events[type].push({fn: fn, isOnce})
  }
  emit(type: string, ...args: any[]) {
    const fnList = this.events[type]
    if (fnList == null) return
    this.events[type] = fnList.filter(item => {
      const {fn, isOnce} = item
      fn(...args)
      return !isOnce
    })
  }
}

只订阅一次

class EventBus {
  private events: {
    [key: string]: Array<{fn: Function, isOnce: boolean}>
  }

  constructor() {
    this.events = {}
  }
  on(type: string, fn: Function, isOnce:boolean=false){
    const events = this.events
    if (events[type] == null) {
      this.events[type] = []
    }
    this.events[type].push({fn: fn, isOnce})
  }
  once(type: string, fn: Function) {
    this.on(type, fn, true)
  }
  emit(type: string, ...args: any[]) {
    const fnList = this.events[type]
    if (fnList == null) return
    this.events[type] = fnList.filter(item => {
      const {fn, isOnce} = item
      fn(...args)
      return !isOnce
    })
  }
}

取消订阅

class EventBus {
  private events: {
    [key: string]: Array<{fn: Function, isOnce: boolean}>
  }

  constructor() {
    this.events = {}
  }
  on(type: string, fn: Function, isOnce:boolean=false){
    const events = this.events
    if (events[type] == null) {
      this.events[type] = []
    }
    this.events[type].push({fn: fn, isOnce})
  }
  once(type: string, fn: Function) {
    this.on(type, fn, true)
  }
  emit(type: string, ...args: any[]) {
    const fnList = this.events[type]
    if (fnList == null) return
    this.events[type] = fnList.filter(item => {
      const {fn, isOnce} = item
      fn(...args)
      return !isOnce
    })
  }
  off(type: string, fn: Function) {
    this.events[type] = this.events[type].filter(item => {
      return item.fn !== fn
    })
  }
}

取消订阅某个事件

class EventBus {
  private events: {
    [key: string]: Array<{fn: Function, isOnce: boolean}>
  }

  constructor() {
    this.events = {}
  }
  on(type: string, fn: Function, isOnce:boolean=false){
    const events = this.events
    if (events[type] == null) {
      this.events[type] = []
    }
    this.events[type].push({fn: fn, isOnce})
  }
  once(type: string, fn: Function) {
    this.on(type, fn, true)
  }
  emit(type: string, ...args: any[]) {
    const fnList = this.events[type]
    if (fnList == null) return
    this.events[type] = fnList.filter(item => {
      const {fn, isOnce} = item
      fn(...args)
      return !isOnce
    })
  }
  off(type: string, fn: Function) {
    // 如果没传 函数就是解除所有
    if (!fn) {
      this.events[type] = []
    }else {
      this.events[type] = this.events[type].filter(item => {
        return item.fn !== fn
      })
    }
  }
}

单例模式应用

在上层实例中单例

将事件总线引入到上层实例使用,只需要保证在一个上层实例中只有一个 EventBus,如果上层实例有多个,意味着有多个事件总线,但是每个上层实例管控自己的事件总线。
首先在上层实例中建立一个变量用来存储事件总线,只在第一次使用时初始化,后续其他模块使用事件总线时直接取得这个事件总线实例。

// 上层实例
class LWebApp {
  private _eventBus?: EventBus;

  constructor() {}

  public getEventBus() {
    // 第一次初始化
    if (this._eventBus == undefined) {
      this._eventBus = new EventBus();
    }

    // 后续每次直接取唯一一个实例,保持在LWebApp实例中单例
    return this._eventBus;
  }
}

// 使用
const eventBus = new LWebApp().getEventBus();

在全局中单例

有时候我们希望不管哪一个模块想使用我们的事件总线,我们都想这些模块使用的是同一个实例,这就是全局单例,这种设计能更容易统一管理事件。
写法同上面的类似,区别是要把 _eventBus 和 getEventBus 转为静态属性。使用时无需实例化 EventBusTool 工具类,直接使用静态方法就行了。

// 上层实例
class EventBusTool {
  private static _eventBus?: EventBus;

  constructor() {}

  public static getEventBus(): EventBus {
    // 第一次初始化
    if (this._eventBus == undefined) {
      this._eventBus = new EventBus();
    }

    // 后续每次直接取唯一一个实例,保持全局单例
    return this._eventBus;
  }
}

// 使用
const eventBus = EventBusTool.getEventBus();

2周刷完100道前端优质面试真题,双越老师力作

链接:https://pan.baidu.com/s/1Fr4TUipNKGyaZxssKIkc3w
提取码:ylsp

也欢迎使用我的小程序,惊喜不断!

xcxm.jpg

标签:面试题,const,string,Bus,events,type,Event,fn,isOnce
From: https://www.cnblogs.com/buxiugangzi/p/17116955.html

相关文章

  • java面试题(五)
    1.1为什么Java代码可以实现一次编写、到处运行?参考答案JVM(Java虚拟机)是Java跨平台的关键。在程序运行前,Java源代码(.java)需要经过编译器编译成字节码(.class)。在程序运行时,JV......
  • java面试题(六)
    1.11int和Integer有什么区别,二者在做==运算时会得到什么结果?参考答案int是基本数据类型,Integer是int的包装类。二者在做==运算时,Integer会自动拆箱为int类型,然后再进行比较......
  • 为什么这11道JVM面试题这么重要(附答案)
    本文内容整理自博学谷狂野架构师运行时数据区都包含什么虚拟机的基础面试题程序计数器Java虚拟机栈本地方法栈Java堆方法区程序计数器程序计数器是线程......
  • Python常见面试题(持续更新 23-2-13)
    Python常见面试题(持续更新23-2-13)参考资料https://github.com/taizilongxu/interview_pythonhttps://github.com/hantmac/Python-Interview-Customs-Collectionhtt......
  • php经典面试题
    什么是面向对象?  面向对象OO=面向对象的分析OOA+面向对象的设计OOD+面向对象的编程OOP;通俗的解释就是“万物皆对象”,把所有的事物都看作一个个可以独立的对象(单......
  • Bus集成webhooks实现自动刷新
    文章目录​​1、配置webhooks​​​​2、下载natapp客户端之后​​​​3、在远程仓库中添加webhooks​​​​4、自动刷新测试​​​​4.1在测试之前先访问测试的controller......
  • Spring Cloud Bus消息总线
    SpringCloudBus消息总线​​1、Bus消息总线​​​​2、实现刷新配置原理​​​​3、搭建RabbitMQ服务​​​​3.0下载rabbitmq安装包(使用docker安装更方便)​​​​3.1......
  • 百度前端常考vue面试题(附答案)
    怎么实现路由懒加载呢这是一道应用题。当打包应用时,JavaScript包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问时才加......
  • 高级前端二面vue面试题(持续更新中)
    action与mutation的区别mutation是同步更新,$watch严格模式下会报错action是异步操作,可以获取数据后调用mutation提交最终数据MVVM的优缺点?优点:分离......
  • 前端react面试题(边面边更)
    diff算法是怎么运作每一种节点类型有自己的属性,也就是prop,每次进行diff的时候,react会先比较该节点类型,假如节点类型不一样,那么react会直接删除该节点,然后直接创建新的节点......