Publish Subscription Mode EventEmitter

Node. The events module of JS provides an external EventEmitter object for Node. Events in JS are managed uniformly. Because Node.js uses event-driven mechanisms, and EventEmitter is Node.js implements the foundation of event driven. On the basis of EventEmitter, Node. Almost all modules in JS inherit this class to implement an asynchronous event-driven architecture.

Example

var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('say',function(name){
    console.log('Hello',name);
})
eventEmitter.emit('say','Jack');

API for EventEmitter Module

Comparison of addListener and removeListener, on and off methods

The addListener method adds a listener for a specified event, which is essentially the same function as the on method, which is actually an alias for the addListener method. Both are implemented in the same way, while the removeListener method is used to remove the listener for an event, and off is also an alias for removeListener.

var events = require("events")
const {
    emit
} = require("process")
var emitter = new events.EventEmitter()

function hello1(name) {
    console.log(" 1", name)
}

function hello2(name) {
    console.log("2", name)
}

emitter.addListener("say", hello1)
emitter.addListener("say", hello2)

emitter.emit("say", "jake")
// 1 jake
// 2 jake
emitter.removeListener("say",hello1)
emitter.emit("say","jake") // 2 jake

removeListener and removeAllListeners

The removeListener method refers to removing one listener for a specified event, while removeAllListeners refers to removing all listeners for a specified event.

emitter.removeAllListeners('say');
emitter.emit('say','John');
//removeAllListeners removes all listening on the say event
//So there is no output

on and once method differences

The difference between on and once is that on's method continuously listens for events to which a listener is added for a given event. The once method adds listeners, which are eliminated after listening once.

emitter.once('see',hello);
emitter.emit('see','Tom');
//hello Tom will only be output once

Implement an EventEmitter

function EventEmitter() {
    this.__events = {}
}
EventEmitter.VERSION = '1.0.0';

EventEmitter.prototype.on = function (eventName, listener) {
    if (!eventName || !listener) return;
    // Determine whether the callback listener is a function
    if (!isValidListener(listener)) {
        throw new TypeError('listener must be a function');
    }

    var events = this.__events;
    var listeners = events[eventName] = events[eventName] || [];
    var listenerIsWrapped = typeof listener === 'object';
    // Do not add events repeatedly to determine if they are the same
    if (indexOf(listeners, listener) === -1) {
        listeners.push(listenerIsWrapped ? listener : {
            listener: listener,
            once: false
        });
    }
    return this;
};

// Determine if it is a legitimate listener
function isValidListener(listener) {
    if (typeof listener === 'function') {
        return true;
    } else if (listener && typeof listener === 'object') {
        return isValidListener(listener.listener);
    } else {
        return false;
    }
}

// As the name implies, determine if a new custom event exists
function indexOf(array, item) {
    var result = -1
    item = typeof item === 'object' ? item.listener : item;
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].listener === item) {
            result = i;
            break;
        }
    }
    return result;
}

The core idea of the on method is that when a call subscribes to a custom event, push the custom event to this. u once it is valid through validation Evets is stored in this object, so when you need to start, you can get u directly from The listener callback function for the corresponding event in events, which can then be executed directly to achieve the desired effect.

emit,off

EventEmitter.prototype.emit = function(eventName, args) {
    // Get callback functions for corresponding custom events directly from internal objects
    var listeners = this.__events[eventName];
    if (!listeners) return;
    // Multiple listener s need to be considered
    for (var i = 0; i < listeners.length; i++) {
        var listener = listeners[i];
        if (listener) {
            listener.listener.apply(this, args || []);
            // Special handling of true once in listener
            if (listener.once) {
                // No more executions after one execution
                this.off(eventName, listener.listener)
            }
        }
    }
    return this;
};

EventEmitter.prototype.off = function(eventName, listener) {
    var listeners = this.__events[eventName];
    if (!listeners) return;
    var index;
    for (var i = 0, len = listeners.length; i < len; i++) {
       if (listeners[i] && listeners[i].listener === listener) {
          index = i;
          break;
       }
   }

   // Key to off, remove binding events from listeners array
   if (typeof index !== 'undefined') {
        listeners.splice(index, 1, null)
   }
   return this;

};

Emi is actually handled by apply executing the corresponding custom event. In the process of execution, the custom event bound by the once method is specially handled. When the once is true, the off method is triggered to unbind the custom event, so as to achieve the effect of one execution of the custom event.

once,alloff

EventEmitter.prototype.once = function(eventName, listener){
    // Direct call to on method, once parameter passed in true, once processing after execution
     return this.on(eventName, {
         listener: listener,
         once: true
     })
 };

EventEmitter.prototype.allOff = function(eventName) {
     // If the eventName exists, empty its corresponding listeners array directly
     if (eventName && this.__events[eventName]) {
         this.__events[eventName] = []
     } else {
         this.__events = {}
     }
};

The once method is essentially a call to the on method, except that the parameters passed in distinguish between one execution and another. When the emit method is triggered again, the once binding is executed once before it is unbound.
The alloff method is also well understood, that is, the internal u The events object is emptied, after which the callback function cannot be triggered if the custom event is triggered again.

Keywords: Javascript node.js Front-end ECMAScript

Added by ljschrenk on Mon, 27 Dec 2021 19:57:16 +0200