One, foreword

Mini-signals is a lightweight, fast library of publish-subscribe patterns. As a qualified frontend, you should be familiar with the publish-subscribe model.

The publish-subscribe pattern defines one-to-many dependencies between objects and can be used to solve the problem of coupling between objects.

From the DOM event system, to the Node.js Events module, to the current popular MVVM architecture pattern, publish-subscribe pattern is everywhere.

Using some JavaScript basics, you can quickly implement a simple publish-subscribe model:

  function EventEmitter ({

    this.events = {};

  }



  EventEmitter.prototype.on = function (event, fn{

    const { events } = this;  

    if(! events[event]) {

      events[event] = [];

    }



    events[event].push(fn);

  }



  EventEmitter.prototype.emit = function (event, ... args{

    const { events } = this;

    const listeners = events[event];

    if(! listeners || listeners.length ===0) {

      return;

    }



    for (let i = 0; i < listeners.length; i++) {

      listeners[i].apply(this, args);

    }

  }

Copy the code

So how does Mini-signals differ from most publish-subscribe implementations? This article takes you step-by-step.

Two, basic use

Before exploring the source, you need to know how to use Mini-Signals:

  const signal = new MiniSignals();



  signal.add(task);

  signal.dispatch('foo'.'bar');



  function task(foo, bar{

    // do something

  }

Copy the code

Most students are used to the following ways:

  const events = new EventEitter();

  events.on('eventname', task);

  events.emit('eventname'.'foo'.'bar');

Copy the code

In terms of usage alone, Mini-signals has the following advantages:

  • No additional constants are required to manage publish-subscribe event names.
  • Events are no longer managed through a bus, and an instance corresponds to an independent event container, which reduces the complexity of the program to a certain extent.

Bidirectional linked list management event monitoring

Mini-signals does not directly create an array on the MiniSignal object to manage event listeners.

class MiniSignal {

  constructor () {

    // First and last

    this._head = this._tail = undefined;

  }

}

Copy the code

Instead, you choose to implement a simple “bidirectional linked list” to manage event listening on the event container. Since the bidirectional linked list node needs to record its precursor and successor nodes, you need the MiniSignalBinding class to create node instances:

class MiniSignalBinding {

  constructor (fn, once = false, thisArg) {

    this._fn = fn;

    // Whether the callback function is executed only once

    this._once = once;

    this._thisArg = thisArg;

    // Records the precursors and successors of the current node

    this._next = this._prev = null;

    // The owning event container

    this._owner = null;

  }

  // Unbind the method

  detach () {

    if (this._owner === nullreturn false;

    this._owner.detach(this);

    return true;

  }



}

Copy the code

MiniSignalBinding internally records the precursor and successor nodes using _prev and _next, and the event container to which the current node belongs using the _owner property.

This set of operations is relatively professional.

Register event listener

MiniSignal provides the add method to register event listeners:

  MiniSignal.prototype.add = function (fn, thisArg = null{

    if (typeoffn ! = ='function') {

      throw new Error('MiniSignal#add(): First arg must be a Function.');

    }

    return _addMiniSignalBinding(this.new MiniSignalBinding(fn, false, thisArg));

  }

Copy the code

Once you have created the node object, you need to update its precursor node, its successor node, its owning event container, and you also need to update the head and tail nodes saved in the MiniSignal:

  function _addMiniSignalBinding (self, node{

    if(! self._head) {

      self._head = node;

      self._tail = node;

    } else {

      self._tail._next = node;

      node._prev = self._tail;

      self._tail = node;

    }



    node._owner = self;



    return node;

  }

Copy the code

V. Distribution events

MiniSignal sends events through the list and then executes the callback function stored in the node:

  dispatch () {

    let node = this._head;



    if(! node)return false;



    while (node) {

      if (node._once) this.detach(node);

      node._fn.apply(node._thisArg, arguments);

      node = node._next;

    }



    return true;

  }

Copy the code

In addition, for the event listening that only needs to be performed once, the untying operation needs to be performed simultaneously.

Six, untying event monitoring

The untying operation requires deleting the linked list and updating the successor pointer of the precursor node and the precursor pointer of the successor node:

  detach (node) {

    if(! (nodeinstanceof MiniSignalBinding)) {

      throw new Error('MiniSignal#detach(): First arg must be a MiniSignalBinding object.');

    }

    if(node._owner ! = =thisreturn this;



    if (node._prev) node._prev._next = node._next;

    if (node._next) node._next._prev = node._prev;



    if (node === this._head) {

      this._head = node._next;

      if (node._next === null) {

        this._tail = null;

      }

    } else if (node === this._tail) {

      this._tail = node._prev;

      this._tail._next = null;

    }



    node._owner = null;

    return this;

  }

Copy the code

Seven,

This is the core code of the Mini-signals library, very lightweight.

MiniSignal also has some advantages over most publish-subscribe implementations:

  • The use of bidirectional linked lists to manage event listeners, thus introducing a separate object to maintain each event listener function, providing readability of the program.
  • A separate event container, compared with the convention of event names, does not need to maintain a large number of constant event names, to a certain extent, reduce the complexity of the program, improve the maintainability of the program.

The above is the content of this article, I hope to bring you help, welcome to “attention”, “like”, “forward”.