One article learned about component communication - publish-subscribe model

Drive data flow using the "publish-subscribe" pattern

The "publish-subscribe" model can be described as the "panacea" to solve communication problems, and it is widely used in the front-end world, such as:

  • socket.ioThe module that exploded in the past two years is a typical implementation of the cross-end publish-subscribe model;

  • Node.jsIn , many native modules are also EventEmitterimplemented based on the base class;

  • However, the most well-known one should be the "global event bus" that is generalized as a routine operation Vue.jsin EventBus.

Although the names of these applications are different, the core is the same, which is the "publish-subscribe" model to be mentioned below.

Understand the publish-subscribe mechanism of events

The early and most widely used publish-subscribe mechanism should be in browser DOMevents . I believe that students who have experience in native JavaScriptdevelopment will be familiar with the following usages:

target.addEventListener(type, listener, useCapture);

By calling addEventListenerthe method , an event listener can be created, and this action is "subscribe". For example I can listen for click(click) events:

el.addEventListener("click", func, false);

In this way, when clickthe event is triggered, the event will be "published", and then trigger functhe function that listens to this event. This is the simplest publish-subscribe case.

The advantage of using the publish-subscribe model is that the location of listening to events and the location of triggering events are not limited, as long as they are in the same context, they can perceive each other. This feature is very suitable for the scenario of "arbitrary component communication".

Publish-subscribe model APIdesign ideas

Through the previous explanation, it is not difficult to see that there are two key actions in the publish-subscribe model: event monitoring (subscription) and event triggering (publishing). These two actions naturally correspond to two basic APImethods

  • addListener(): The listener responsible for registering the event, specifying the callback function when the event is triggered.

  • emit(): Responsible for triggering events, you can pass parameters to make it carry data when triggered.

Finally, it is always unreasonable to only enter and exit, and consider a removeListener()method , which can be used to delete unused listeners when necessary:

  • removeListener(): Responsible for the removal of the listener.

Publish-subscribe model coding implementation

Before writing code, you must first clear your mind. Here, EventEmitterthe big problem of "realization" is broken down into three specific small problems, which will be solved one by one below.

Question 1: How to deal with the correspondence between events and listener functions?

When it comes to "correspondence", one should think of "mapping". JavaScriptIn , processing "mapping" is mostly done with objects. So you need to set an object globally to store the relationship between events and listener functions:

class EventBus {
    
    
    constructor() {
    
    
        // events 用来存储事件和监听函数之间的关系
        this.events = this.events || new Object();
    }
}

Question 2: How to implement subscription?

The so-called "subscription" is the process of registering an event listener function. This is a "write" operation, specifically, to write the event and the corresponding listener function into events:

EventBus.prototype.addListener = function (type, fun) {
    
    
    const e = this.events[type];

    if (!e) {
    
       //如果从未注册过监听函数,则将函数放入数组存入对应的键名下
        this.events[type] = [fun];
    } else {
    
      //如果注册过,则直接放入
        e.push(fun);
    }
};

Question 3: How to realize the release?

The subscription operation is a "write" operation, and correspondingly, the publish operation is a "read" operation. The essence of publishing is to trigger the listener function installed on a certain event. What needs to be done is to find the listener function queue corresponding to this event, and execute the in the queue one funby

EventBus.prototype.emit = function (type, ...args) {
    
    
    let e;
    e = this.events[type];
    // 查看这个type的event有多少个回调函数,如果有多个需要依次调用。
    if (!e) {
    
    
        return
    } else if (Array.isArray(e)) {
    
    
        for (let i = 0; i < e.length; i++) {
    
    
            e[i].apply(this, args);
        }
    }
};

A fully functional core EventEmitteris as follows :

class EventBus {
    
    
    constructor() {
    
    
        this.events = this.events || new Object();
    }
}
//首先构造函数需要存储event事件,使用键值对存储
//然后需要发布事件,参数是事件的type和需要传递的参数
EventBus.prototype.emit = function (type, ...args) {
    
    
    let e;
    e = this.events[type];
    // 查看这个type的event有多少个回调函数,如果有多个需要依次调用。
    if (!e) {
    
    
        return
    } else if (Array.isArray(e)) {
    
    
        for (let i = 0; i < e.length; i++) {
    
    
            e[i].apply(this, args);
        }
    }
};
//然后需要写监听函数,参数是事件type和触发时需要执行的回调函数
EventBus.prototype.addListener = function (type, fun) {
    
    
    const e = this.events[type];

    if (!e) {
    
       //如果从未注册过监听函数,则将函数放入数组存入对应的键名下
        this.events[type] = [fun];
    } else {
    
      //如果注册过,则直接放入
        e.push(fun);
    }
};
EventBus.prototype.removeListener = function (type) {
    
    
    delete this.events[type]
}
// 实例化
const eventBus = new EventBus();
export default eventBus;

test

The following eventBusis a simple test to listen to and trigger an event named "test":

import eventBus from 'EventBus'

// 编写一个简单的 fun
const testHandler = function (params) {
    
    
    console.log(`test事件被触发了,testHandler 接收到的入参是${
      
      params}`);
};

// 监听 test 事件
eventBus.addListener("test", testHandler);

// 在触发 test 事件的同时,传入希望 testHandler 感知的参数
eventBus.emit("test", "newState");

The above code will output the part enclosed by the red rectangle below as the running result:

insert image description here
It can be seen from this that EventEmitterthe instance already has the publish-subscribe capability, and the execution results meet expectations.

Guess you like

Origin blog.csdn.net/qq_16525279/article/details/127493819