理解js发布订阅模式

引言

js是一门单线程语言,如果没有异步操作,非得卡死不可。早期的js异步编程方法大概有四种:

  • 回调函数
  • 事件监听
  • 发布订阅模式
  • Promise对象

我们可以初步认为发布订阅模式是用来实现异步编程的一种方式。

什么是发布/订阅模式?

在软件架构中,发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。

简单点来说​​发布/订阅模式​​其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。订阅者通过把订阅的事件传递给订阅中心,订阅中心统一管理这个订阅事件队列,并在发布内容的时候把内容推送给所有的订阅事件。

图解: 算我欠你们的,下次有时间再画。

代码理解:

用代码的角度来解释就是:
有一个对象/数组,被当做订阅中心,里面存放用户订阅的内容(事件),可以有多个事件。

订阅: 用户将事件存入订阅中心,事件名是唯一的,具体的事件是一个函数。
接受参数(事件名,fn)
存入格式 key :[fn,fn,fn] ,其中key是事件名,一定要确保事件名唯一。

发布:将数据推送给订阅中心下所有key为指定事件名的数组中的所有方法。
接受参数,(事件名,数据),事件名用来匹配订阅中心订阅的事件,data数据交给事件里的函数来执行。

取消订阅: 接受参数(事件名,fn)。将事件数组中该方法清空就行,需要匹配一下用户传入的fn,当用户不传入fn时,则直接清空该事件名下所有事件(方法)
------简单点的代码----

  const bus = {
      list: [],

      //订阅
      subscribe(cb) {
        this.list.push(cb);
      },

      //发布
      publish(arg) {
        this.list.forEach((cb) => {
          Object.prototype.toString.call(cb) === "[object Function]" && cb(arg);
        });
      },
    };

    //订阅者
    bus.subscribe((argument) => {
      console.log("我拿到的参数是", argument);
    });
    bus.subscribe((argument) => {
      console.log("我拿到的参数是", argument);
    });
    bus.subscribe((argument) => {
      console.log("我拿到的参数是", argument);
    });
    bus.subscribe((argument) => {
      console.log("我拿到的参数是", argument);
    });
    //console.log("list====", bus.list);
    //发布者
    bus.publish("我是发布者");

复杂点的代码

 class Public {
      static events = {};
      on(eventName, fn) {
        if (!this.events[eventName]) {
          this.events[eventName] = this.events[eventName] || [];
          this.events[eventName].push(fn);
        }
      }
      emit(eventName, data) {
        if (this.events[eventName]) {
          this.events[eventName].forEach((fn) => fn(data));
        }
      }
      off(eventName, fn) {
        if (this.events[eventName]) {
          const newEvent = fn
            ? this.events[eventName].filter((item) => item !== fn)
            : [];
          this.events[eventName] = newEvent;
        }
      }
    }

----ts版本----

// 发布订阅中心, on-订阅, off取消订阅, emit发布, 内部需要一个单独事件中心caches进行存储;
interface CacheProps {
  [key: string]: Array<((data?: unknown) => void)>;
}

class Observer {
  private caches: CacheProps = {}; // 事件中心
  on (eventName: string, fn: (data?: unknown) => void){ // eventName事件名-独一无二, fn订阅后执行的自定义行为
    this.caches[eventName] = this.caches[eventName] || [];
    this.caches[eventName].push(fn);
  }

  emit (eventName: string, data?: unknown) { // 发布 => 将订阅的事件进行统一执行
    if (this.caches[eventName]) {
      this.caches[eventName].forEach((fn: (data?: unknown) => void) => fn(data));
    }
  }

  off (eventName: string, fn?: (data?: unknown) => void) { // 取消订阅 => 若fn不传, 直接取消该事件所有订阅信息
    if (this.caches[eventName]) {
      const newCaches = fn ? this.caches[eventName].filter(e => e !== fn) : [];
      this.caches[eventName] = newCaches;
    }
  }

}

这里有一篇很好的博客也可以助于理解:
https://blog.csdn.net/m0_63657524/article/details/122312412

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

godlike-icy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值