EventBus的实现

2021/11/19 Interview

最近看到过这样一个有意思的实现,使用 ES6 实现 EventBus。

题目的具体要求是这样的:

const e = new EventBus();

function fn1() {
console.log("fn1");
}
function fn2() {
console.log("fn2");
}
e.on("a", fn1);
e.once("a", fn2);
e.emit("a"); // fn1,fn2
e.emit("a"); // fn1
e.off("a", fn1);
e.emit("a"); // null

要求分析

  • 支持四个方法:on,once,emit,off
  • 是按照添加的顺序依次执行方法;
  • once 添加的只会执行一次

简单实现

interface CallBackInfo {
  (): void;
}

interface Listener {
  cb: CallBackInfo;
  options?: Options;
}

interface Options {
  once?: boolean;
}

class EventBus {
  private listener: { [key: string]: Listener[] } = {};

  on(eventType: string, callback: CallBackInfo) {
    this.add(eventType, callback);
  }

  once(eventType: string, callback: CallBackInfo) {
    this.add(eventType, callback, { once: true });
  }

  private add(eventType: string, callback: CallBackInfo, options?: Options) {
    if (!Array.isArray(this.listener[eventType])) {
      this.listener[eventType] = [];
    }
    this.listener[eventType].push({
      cb: callback,
      options,
    });
  }

  emit(eventType: string) {
    const cbs = this.listener[eventType];
    if (!Array.isArray(cbs) || cbs.length === 0) {
      return null;
    }
    cbs.forEach((item) => {
      if (item.options && item.options.once) {
        this.off(eventType, item.cb);
      }
      item.cb();
    });
  }

  off(eventType: string, callback: CallBackInfo) {
    const cbs = this.listener[eventType];
    if (!Array.isArray(cbs) || cbs.length === 0) {
      return;
    }
    const curIndex = cbs.findIndex((item) => callback === item.cb);
    if (curIndex >= 0) this.listener[eventType].splice(curIndex, 1);
  }
}
const e = new EventBus();

function fn1() {
  console.log("fn1");
}
function fn2() {
  console.log("fn2");
}
e.on("a", fn1);
e.once("a", fn2);
e.emit("a"); // fn1,fn2
e.emit("a"); // fn1
e.off("a", fn1);
e.emit("a"); // null

使用示例运行后得到了期望的结果。

Search

    Table of Contents