前端中的设计模式——发布订阅模式

在前端中观察者通常抽象为事件更具实用性,但这种模式会有一个问题.

假设想在登陆成功后通知组件A、B、C更新view(A、B、C未登录时view处于缺省状态).

  1. 用观察者模式的话

    const ob = new Observable()
    // A、B、C进行一波订阅
    ob.add('update1', () => {
      console.log('login successful!')
    })
    ob.add('update2', () => {
      console.log('login successful!')
    })
    ob.add('update3', () => {
      console.log('login successful!')
    })
    // 通知A、B、C
    ob.notify('update1')
    ob.notify('update2')
    ob.notify('update3')
    

    可以看出,登陆成功后想通知组件A、B、C更新view.前提得三个组件都进行订阅,并发布三次通知,才能实现.

  2. 希望的做法(猜想模式):

    const ob = new Observable()
    const update = new Type()
    // 组件a
    update.add(() => {
      console.log('login successful 1!')
    })
    // 组件b
    update.add(() => {
      console.log('login successful 2!')
    })
    // 组件c
    update.add(() => {
      console.log('login successful 3!')
    })
    ob.add(update)
    ob.notify(update)
    
  3. 分析:

    现有模式类比描述
    观察者模式微商模式用户A、B、C订阅了商品x(这个商品x的订阅是由店主手动维护的),当商品x到货后,店主需要逐个通知对应的用户(店主需要知道哪些用户订阅了商品x).
    猜想模式淘宝模式用户A、B、C关注了商品x(这个商品x的订阅是由商品模块自身维护的),当商品x到货后,店主只用点击对应的商品到货通知,所有关注商品x的用户就可以收到通知.
  4. 区别:

    通过一个中间层(商品模块自身),让用户和店主进行解耦.店主不需要知道哪些用户订阅了商品x,这个问题由中间层自己处理.而店主只需在对应商品到货时发布对应商品的到货通知就可以达到对所有关注了此商品的用户推送消息.

  5. 发布订阅模式的引入

    1. 理解: 淘宝模式的抽象化

    2. 图解
      lzdUrq.png

    3. 实现:

      // 事件总线(调度中心)
      class EventBus {
        constructor() {
          this.subscribers = [];
        }
      
        $on(fn) {
          this.subscribers.push(fn);
        }
      
        $off(fn) {
          this.subscribers.forEach((_fn, index) => {
            fn === _fn && this.subscribers.splice(index, 1);
          })
        }
      
        $once(fn) {
          fn.once = true;
          this.subscribers.push(fn);
        }
      
        $notify(params) {
          this.subscribers.forEach(fn => {
            fn(params);
            fn.once && this.$off(fn);
          });
        }
      }
      // 发布
      class Pub {
        constructor() {
          this.events = [];
        }
      
        $increase(event) {
          this.events.push(event);
        }
      
        $broadcast(event, ...params) {
          this.events.forEach(_event => {
            event === _event && _event.$notify(...params);
          })
        }
      }
      
      module.exports = {
        Pub: new Pub(),
        EventBus
      };
      
    4. 使用

      const ev1 = new EventBus();
      const ev2 = new EventBus();
      // 订阅主题
      ev1.$on(data => {
        console.log(`${data}==>订阅者1收到消息了`);
      });
      ev1.$on(data => {
        console.log(`${data}==>订阅者2收到消息了`);
      });
      ev2.$on(data => {
        console.log(`${data}==>订阅者2收到消息了`);
      });
      ev2.$once(data => {
        console.log(`${data}==>订阅者3收到消息了`);
      });
      // 加入主题
      Pub.$increase(ev1);
      Pub.$increase(ev2);
      // 发布主题
      Pub.$broadcast(ev1, '主题1更新了~');
      Pub.$broadcast(ev2, '主题2更新了~');
      Pub.$broadcast(ev2, '主题2再次更新了~');
      /* 
      主题1更新了~==>订阅者1收到消息了
      主题1更新了~==>订阅者2收到消息了
      主题2更新了~==>订阅者2收到消息了
      主题2更新了~==>订阅者3收到消息了
      主题2再次更新了~==>订阅者2收到消息了
      */
      
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值