JavaScript手写系列(二)———EventBus

前言

Vue中的组件传参是日常开发中常遇到的需求,其中EventBus事件总线就是其中非常好用的一种,之前其实是比较排斥这种用法的,就是因为用的少,不了解所以出于对未知事物的恐惧,比较排斥。最近刷到一篇手写EventBus的文章,看完才明白其中的大概原理,今天就以我自己的理解来给大家讲讲基本实现。

我们可以把EventBus简单理解为一个公众号,其中公众号作者拥有发布($emit)消息的能力,用户拥有订阅($on)公众号的能力,公众号作者发布文章后,用户会收到文章内容推送,如果用户不喜欢推送的文章则可以选择取消订阅($off)公众号的能力。接下来我们就来简单实现一下这些功能。

代码实现

function EventBus() {
  this.eventObj = {}; // 定义事件存储列表
  this.callbackId = 0; // 定义事件id  可以理解为公众号订阅者人数
}

// 订阅
EventBus.prototype.$on = function(key, callback) {
  if (this.eventObj[key] === undefined) {
    this.eventObj[key] = {}; // 如果不存在key的事件列表 则初始化为空  可以理解为 一个公众号可以有多个人订阅
  }
   const callbackIndex = this.callbackId++; // 先赋值再添加 每添加一个订阅者 人数加1
  this.eventObj[key][callbackIndex] = callback; //将回调函数添加到事件列表中 可以理解为添加订阅公众号人数,并为每个订阅者提供通知服务
  return callbackIndex; // 返回订阅者id 可以理解为是第几个订阅的人
};

// 发布
EventBus.prototype.$emit = function(key, ...args) {
  const EventList = this.eventObj[key]; // 获取本次发布内容对应的所有订阅者
  Object.keys(EventList).forEach((fnKey) => {
    EventList[fnKey](...args); // 执行传入的函数  可以理解为挨个通知所有订阅者本次发布的内容
    if (fnKey.indexOf("once") > -1) {
      // 只执行一次的订阅 执行完就删除
      delete EventList[fnKey];
    }
  });
};

// 取消
EventBus.prototype.$off = function(key, id) {
  delete this.eventObj[key][id]; // 删除订阅事件 可以理解为取消通知订阅者
  if (this.eventObj[key].length === 0) {
    // 如果没人关注公众号 就删除该事件
    delete this.eventObj[key];
  }
};

// 执行一次
EventBus.prototype.$once = function(key, callback) {
  if (this.eventObj[key] === undefined) {
    // 未订阅过该事件
    this.eventObj[key] = {};
  }
  const callbackIndex = this.callbackId++; // 先赋值再添加 每添加一个订阅者 人数加1
  this.eventObj[key]["once" + callbackIndex] = callback; //将回调函数添加到事件列表中 可以理解为添加订阅公众号人数,并为每个订阅者提供通知服务,使用once标记只订阅一条消息的订阅者
  return callbackIndex; // 返回订阅者id 可以理解为是第几个订阅的人
};

代码验证

接下来我们通过几个例子来验证这几个实现的功能。
1.发布、订阅

const eventBus = new EventBus();

eventBus.$on("gongzhonghao1", (content) => {
  console.log(`用户1订阅了gongzhonghao1,${content}`);
});
eventBus.$on("gongzhonghao1", (content) => {
  console.log(`用户2订阅了gongzhonghao1,${content}`);
});
eventBus.$emit("gongzhonghao1", "文章内容1");
eventBus.$emit("gongzhonghao1", "文章内容2");

公众号发布了两次消息,两个用户都收到了两条消息。
在这里插入图片描述

取消订阅

const eventBus = new EventBus();

eventBus.$on("gongzhonghao1", (content) => {
  console.log(`用户1订阅了gongzhonghao1,${content}`);
});
const id = eventBus.$on("gongzhonghao1", (content) => {
  console.log(`用户2订阅了gongzhonghao1,${content}`);
});

eventBus.$emit("gongzhonghao1", "文章内容1");

eventBus.$off('gongzhonghao1', id)  

eventBus.$emit("gongzhonghao1", "文章内容2");

在发布第二条消息之前取消了订阅公众号 所以用户2只收到了公众号1发布的第一条内容
在这里插入图片描述

3.订阅一次


const eventBus = new EventBus();

eventBus.$on("gongzhonghao1", (content) => {
  console.log(`用户1订阅了gongzhonghao1,${content}`);
});
 eventBus.$once("gongzhonghao1", (content) => {
  console.log(`用户2订阅了gongzhonghao1,${content}`);
});

eventBus.$emit("gongzhonghao1", "文章内容1");


eventBus.$emit("gongzhonghao1", "文章内容2");

用户2只订阅了一次内容,所以无法收到第二条消息

在这里插入图片描述

参考文章

# 面试官:请手写一个EventBus,让我看看你的代码能力!

猜你喜欢

转载自blog.csdn.net/Salange1/article/details/127523376