理解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

猜你喜欢

转载自blog.csdn.net/qq_43682422/article/details/126410861