发布订阅:灵感来源于 DOM2 事件池机制

  1. 事件池:可以向事件池中追加方法(追加多个不同的方法),当后期事件触发的时候,按照顺序会把这些方法依次执行(也可以从事件池中移除方法);
  2. 追加方法类似 addEventListener;
  3. 移除方法类似 removeEventListener;

图解

  1. 可以把要执行的方法,依次加入到池子中 on(也可以从池子中移除 off),当某个条件到达的时候,通知池子中的方法依次执行 emit;

jQuery 实现

// 创建一个事件池
let $plan = $.Callbacks();

function fn1(n, m) { console.log(1, n, m); }
function fn2(n, m) { console.log(2, n, m); }
function fn3(n, m) { console.log(3, n, m); }

// 向事件池中追加方法(没有做去重处理)
$plan.add(fn1);
$plan.add(fn2);
$plan.add(fn3);
$plan.add(fn3);

// 通知事件池中的方法执行
setTimeout(() => {
    $plan.fire(10, 20);
}, 1000);

js 实现

(function () {
  class EventBus {
    constructor() {
      // 创建一个事件池 {xxx:[],...}
      this.pond = {};
    }

    // 向事件池中追加方法
    $on(type, func) {
      // 每一次加方法的时候,首先看看事件池中是否存在这个类型,不存在就创建
      let pond = this.pond;
      !(type in pond) ? pond[type] = [] : null;
      // 增加方法(去重)
      let pondT = pond[type];
      !pondT.includes(func) ? pondT.push(func) : null;
    }

    // 从事件池中移除方法
    $off(type, func) {
      let pondT = this.pond[type];
      if (!pondT) return;
      for (let i = 0; i < pondT.length; i++) {
        let item = pondT[i];
        if (item === func) {
          // 移除掉(因为追加的时候去重了,所以删除一次就够了,不需要在向后找了)
          // 为了防止数组塌陷,此处不使用 splice(i, 1) 删除,使用 null 赋值即可 
          pondT[i] = null;
          return;
        }
      }
    }

    // 通知事件池中某个类型对应的方法依次执行
    // ...args <=> [].slice.call(arguements,1)
    $emit(type, ...args) {
      let pondT = this.pond[type] || [];
      for (let i = 0; i < pondT.length; i++) {
        let func = pondT[i];
        // 如果不是函数,在容器中移除掉
        if (typeof func !== "function") {
          pondT.splice(i, 1);
          // 因为执行了 splice 导致数组塌陷,导致后面的元素索引全部 -1,让 i 也减 1
          i--;
          continue;
        }
        func.apply(this, args);
      }
    }
  }
  window.EB = new EventBus();
})();
<!-- 测试 -->
<script>
  function fn1() { console.log(1); }
  function fn2() { console.log(2); }
  function fn3() {
    console.log(3);
    EB.$off('AA', fn1);
    EB.$off('AA', fn2);
  }
  function fn4() { console.log(4); }
  function fn5() { console.log(5); }
  function fn6() { console.log(6); }

  EB.$on('AA', fn1);
  EB.$on('AA', fn2);
  EB.$on('AA', fn3);
  EB.$on('AA', fn4);
  EB.$on('AA', fn5);
  EB.$on('AA', fn6);
</script>

应用

  1. 更好的管理项目中的代码,方便维护,方便团队协作,方便扩展…;
  2. 基于发布订阅模式管控,用户登录获取基本信息后逐一需要做的事情;
  3. 双向数据绑定;

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于产品、设计、开发的问题和看法,还有技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程

了解更多

目录

  1. 1. 发布订阅:灵感来源于 DOM2 事件池机制
  2. 2. 图解
  3. 3. jQuery 实现
  4. 4. js 实现
  5. 5. 应用