以最新版mitt源码解读基于发布订阅模式的js事件处理中心(保姆级分步解读)

151 阅读3分钟

为什么要学习这个?

发布订阅模式被广泛用于日常开发的方方面面比如原生事件API、react里的redux等。对我们开发来说也是提供了一个扩展性的思路。

发布订阅模式其实说得简单一点。就是在微博里面,你关注了我,我更新了微博,你会得到推送,就这个意思。

定义

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

mitt源码解读(保姆级分步解读)

"use strict";
exports.__esModule = true;
/**
 * Mitt: Tiny (~200b) functional event emitter / pubsub.
 * @name mitt
 * @returns {Mitt}
 */
function mitt(all) {
  all = all || new Map();
  return {
    /**
     * all就是我们所说的调度中心,为一个map类型的对象。Map对象保存键值对,是键值对的集合, 用于管理订阅者。
     */
    all: all,
    
    /**
     * 这里就是订阅者发布订阅的地方,为传进来的类型注册一个事件处理程序。
     */
    on: function (type, handler) {
      var handlers = all.get(type); // 先去调度中心看看这个类型的事件有没有被注册,并拿到该类型事件处理程序列表
      if (handlers) {
        handlers.push(handler); // 直接在调度中心该类型事件处理程序列表中增加处理方法
      } else {
        all.set(type, [handler]);// 创建一个事件处理程序列表并把处理方法添加进去
      }
    },
    
    /**
     * 删除给定类型的事件处理程序
     * 如果 `handler` 被省略,给定类型的所有处理程序都将被删除。
     */
    off: function (type, handler) {
      var handlers = all.get(type); // 先去调度中心看看这个类型的事件有没有被注册,并拿到该类型事件处理程序列表
      if (handlers) {
        if (handler) {
          handlers.splice(handlers.indexOf(handler) >>> 0, 1); // 这里用到了无符号右移的位运算符
        } else {
          all.set(type, []); // 给定类型的所有处理程序都将被删除
        }
      }
    },
    
    /**
     * 给定类型的所有处理程序调用的地方
     * 如果存在,则在类型匹配的处理程序之后调用“*”处理程序
     *
     * 注意:不支持手动触发“*”处理程序
     */
    emit: function (type, evt) {
      var handlers = all.get(type);// 先去调度中心看看这个类型的事件有没有被注册,并拿到该类型事件处理程序列表
      if (handlers) {
        handlers.slice().map(function (handler) { // 把该类型事件处理程序列表中的处理程序一个一个运行
          handler(evt);
        });
      }
      handlers = all.get("*"); //这个是最新版本新加的功能,可以在调用on方法,也就是注册订阅的时候使用*来表明每次有发布的时候都会触发这个订阅的处理程序
      if (handlers) {
        handlers.slice().map(function (handler) {
          handler(type, evt);
        });
      }
    },
  };
}
exports["default"] = mitt;