【若川视野 x 源码共读】第8期 | mitt、tiny-emitter 发布订阅

82 阅读3分钟

1、mitt

export type EventType = string | symbol;

// An event handler can take an optional event argument
// and should not return a value
export type Handler<T = unknown> = (event: T) => void;
export type WildcardHandler<T = Record<string, unknown>> = (
  type: keyof T,
  event: T[keyof T]
) => void;

// An array of all currently registered event handlers for a type
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
// 通配符事件处理程序列表
export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;

// A map of event types and their corresponding event handlers.
export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
  keyof Events | '*',
    EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
    >;
  
  export interface Emitter<Events extends Record<EventType, unknown>> {
    all: EventHandlerMap<Events>;   //事件处理函数数组
    
    //注册某事件,并监听
    on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
    on(type: '*', handler: WildcardHandler<Events>): void;
    
    //关闭某事件监听
    off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;
    off(type: '*', handler: WildcardHandler<Events>): void;
    
    //触发某事件
    emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
    emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;
}

/**
* Mitt: Tiny (~200b) functional event emitter / pubsub.
* @name mitt
* @returns {Mitt}
*/
export default function mitt<Events extends Record<EventType, unknown>>(
  all?: EventHandlerMap<Events>
): Emitter<Events> {
  type GenericEventHandler =
  | Handler<Events[keyof Events]>
  | WildcardHandler<Events>;
all = all || new Map();

return {
  
  /**
  * A Map of event names to registered handler functions.
  * //所有注册函数
  */
  all,
  
  /**
  * Register an event handler for the given type.
  * @param {string|symbol} type Type of event to listen for, or `'*'` for all events
  * @param {Function} handler Function to call in response to given event
  * @memberOf mitt
  */
  on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
    // 获取 type 对应的的 事件处理函数数组
    const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
    // 存在,说明设置过,handlers 已经是数组,直接 push 进去
    if (handlers) {
      handlers.push(handler);
    }
    else {
      //不存在,注册事件并监听
      all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
    }
  },
    
    /**
    * Remove an event handler for the given type.
    * If `handler` is omitted, all handlers of the given type are removed.
    * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler)
    * @param {Function} [handler] Handler function to remove
    * @memberOf mitt
    */
    off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
      const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
      if (handlers) {
        if (handler) {
          //删除指定的 handler处理函数
          handlers.splice(handlers.indexOf(handler) >>> 0, 1);
        }
        else {
          //删除全部
          all!.set(type, []);
        }
      }
    },
      
      /**
      * Invoke all handlers for the given type.
      * If present, `'*'` handlers are invoked after type-matched handlers.
      *
      * Note: Manually firing '*' handlers is not supported.
      *
      * @param {string|symbol} type The event type to invoke
      * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
      * @memberOf mitt
      */
      emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
        //触发当个事件
        let handlers = all!.get(type);
        if (handlers) {
          (handlers as EventHandlerList<Events[keyof Events]>)
            .slice()
              .map((handler) => {
              handler(evt!);
                      });
        }
        
        //触发所有事件
        handlers = all!.get('*');
        if (handlers) {
          (handlers as WildCardEventHandlerList<Events>)
            .slice()
            .map((handler) => {
            handler(type, evt!);
                    });
        }
      }
};
}

1、调试

const emitter = mitt()

// listen to an event

emitter.on('foo', e => console.log('foo', e))

emitter.on('foo', e => console.log('foo1', e))

// listen to all events

emitter.on('', (type, e) => console.log('' + type, e))

emitter.emit('foo', { a:'b' })

emitter.all.clear() //清除所有事件

emitter.on('foo', onFoo)

emitter.off('foo', onFoo) // unlisten

2、缺点

  1. mitt 支持传入 all 参数,如果 all = {} 而不是 new Map() 那么会报错,不能正常使用,在ts中当然会提醒你
  2. emit(type, [evt])中只能接受一个参数,要是传多个参数需要将多个参数合并成对象传入,然后在事件处理函数中解构

2、tiny-emitter

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.TinyEmitter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  function E () {
    // Keep this empty so it's easier to inherit from
    // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
  }
  
  E.prototype = {
    on: function (name, callback, ctx) {
      var e = this.e || (this.e = {});
      
      (e[name] || (e[name] = [])).push({
        fn: callback,
        ctx: ctx
      });
      
      return this;
    },
    
    once: function (name, callback, ctx) {
      var self = this;
      function listener () {
        self.off(name, listener);
        callback.apply(ctx, arguments);
      };
      
      listener._ = callback
      return this.on(name, listener, ctx);
    },
    
    emit: function (name) {
      var data = [].slice.call(arguments, 1);
      var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
      var i = 0;
      var len = evtArr.length;
      
      for (i; i < len; i++) {
        evtArr[i].fn.apply(evtArr[i].ctx, data);
      }
      
      return this;
    },
    
    off: function (name, callback) {
      var e = this.e || (this.e = {});
      var evts = e[name];
      var liveEvents = [];
      
      if (evts && callback) {
        for (var i = 0, len = evts.length; i < len; i++) {
          if (evts[i].fn !== callback && evts[i].fn._ !== callback)
            liveEvents.push(evts[i]);
        }
      }
      
      // Remove event from queue to prevent memory leak
      // Suggested by https://github.com/lazd
      // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
      
      (liveEvents.length)
        ? e[name] = liveEvents
      : delete e[name];
      
      return this;
    }
  };
  
  module.exports = E;
  module.exports.TinyEmitter = E;
  
},{}]},{},[1])(1)
});

1、调试

consttiny = newE()

// listen to an event

tiny.on('foo', e=>console.log('foo', e))

tiny.on('foo', e=>console.log('foo1', e))

tiny.emit('foo', { a: 'b' })

tiny.once('haha', (type, e) =>console.log('*' + type, e))

tiny.emit('haha', { a:'b' })

tiny.emit('haha', { a:'b' })

触发一次时,循环时会调用fn函数,即listener,关闭监听,并callbak调用argument,返回结果。

functiononFoo() {}

tiny.on('foo', onFoo) // listen

tiny.off('foo', onFoo) // unliste

3、感谢

tinymitter的once方法真的觉得很高级,真的觉得作者处理这一段的时候很厉害,学到了学到了 感谢老师