Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Source code learning as a child and beautiful Mitt began

It’s not that hard to learn the source code, let’s not start with a very large library (Vue/React/..) , it is necessary to learn from this kind of code line library source code is not particularly many, find confidence, find a sense of achievement, slowly to the larger library attack.

For example, shared utils in the Vue3 source code can be read first. The address is as follows:

vue-next/packages/shared/src/index.ts

In the previous article, I learned the simple use of Mitt and learned part of the knowledge point of source code in advance. Today, I will study Mitt source code in detail

Learn the design patterns, some tricks, operators, etc. Learning source code, improve their own.

Mitt source code learning

Mitt warehouse

SRC /index.ts SRC /index.ts SRC /index.ts SRC /index.ts SRC /index.ts

// https://github.com/developit/mitt/src/index.ts

Why mitt

Mitt: Tiny (~200b) functional event emitter / pubsub.

Similar to eventBus used in the VUe2 era,

First of all, ITT is small, small and beautiful, only 200bytes. Second, it supports event monitoring and batch removal, which can be used across frameworks. React, Vue and even jQuery projects can use the same package

SRC /index.ts source code interpretation

The following annotated English annotations for source annotations, with their own interpretation

/ / event types can be: string | symbol
export type EventType = string | symbol;

// An event handler can take an optional event argument and should not return a value
// If the generic type is not specified, the default is (). : top-level type unknown, (is this to avoid the performance cost of type derivation at development time?) , avoid using any. Unknown can be regarded as the security version of any
export type Handler<T = unknown> = (event: T) = > void;

// keyof (see summary 2.1)
// T[keyof T] is actually a union type (see Summary 2.2)
// Record tool function (see Summary 2.3)
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.
// The Map here refers to the Map of ES6, the Map of the new Map, the project can use the 'Command + left mouse button' click on the Map to see the specific content
export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
  keyof Events | The '*',
  EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
>;

export interface Emitter<Events extends Record<EventType, unknown>> {
  all: EventHandlerMap<Events>;

  // Overload (the reason for the overload: handler parameters change depending on whether type is '*')
  on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
  on(type: The '*'.handler: WildcardHandler<Events>): void;

  / / overloaded
  off<Key extends keyof Events>(type: Key, handler? : Handler<Events[Key]>):void;
  off(type: The '*'.handler: WildcardHandler<Events>): void;

  / / overloaded
  emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
  // this means that if type is undefined, undefined is the key; otherwise, the type never represents the type of a value that never exists
  // Emit () should not be simply short for emit('*')
  emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never) :void;
}

/**
 * Mitt: Tiny (~200b) functional event emitter / pubsub.
 * @name mitt
 * @returns {Mitt}* /
// Which one does Events refer to?
Function mitt
      
       () {}
      
export default function mitt<Events extends Record<EventType.unknown> > (all? : EventHandlerMap
       
        ,
       ) :Emitter<Events> {
  type GenericEventHandler =
    // Events[keyof Events] is actually a union type
    // See summary 3.1 for details
    // This is an event handler with one argument
    // (event) => {}
    | Handler<Events[keyof Events]>
    // This is the event handler for two arguments
    // (type, event) => {}
    | WildcardHandler<Events>;

  // Set a default value for all. In general, all must be Map
  all = all || new Map(a);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) {
      / /! Mandatory assertion: indicates that it must exist
      const handlers: Array<GenericEventHandler> | undefined= all! .get(type);
      if (handlers) {
        // Just push it in
        handlers.push(handler);
      } else {
        // Set it if it hasn't been set
        // Note: New Settings should be arrays
        // Why use type assertion?
        // To be consistent with the type of all
        / / in order to consistent with all types of why not EventHandlerList < Events [keyof Events] > | WildCardEventHandlerList < Events >?
        // Because this side is specified type.
        // WildCardEventHandlerList
      
        is used for type '*'
      all! .set(type, [handler] asEventHandlerList<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, or `'*'`
     * @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);

      // error tolerance
      if (handlers) {
        // Delete from array if handler exists
        if (handler) {
          // >>> Unsigned right shift see summary 4
          '-1' >>> 0 => 4294967295
          // If it exists, it can be deleted. If it does not exist, it cannot be deleted
          handlers.splice(handlers.indexOf(handler) >>> 0.1);

          // Reset handlers if they don't exist
        } 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]) {lethandlers = all! .get(type);
      if (handlers) {
        // There must be type assertion, because there is only one argument here
        Handlers are not allowed to modify their handlers (this detail is probably common sense)
        (handlers as EventHandlerList<Events[keyof Events]>).slice().map((handler) = > {
          / /! Mandatory assertion: indicates that it must existhandler(evt!) ; }); }// This is a bit of a technicality, but if I had to implement this library feature, I would probably ignore ithandlers = all! .get(The '*');
      if (handlers) {
        // Type assertion is required here because two arguments are being passed
        (handlers as WildCardEventHandlerList<Events>).slice().map((handler) = > {
          // type actually refers to the type executed
          / /! Mandatory assertion: indicates that it must exist
          handler(type, evt!) ; }); }}}; }Copy the code