Release - Subscription mode is actually a one to many dependency between objects , When the state of an object changes , All objects that depend on it will be notified of state changes .
subscriber (Subscriber) Register the events you want to subscribe to (Subscribe) Go to the dispatch center (Event Channel), When the publisher (Publisher) Release the incident (Publish Event) Go to the dispatch center , That is, when the event is triggered , It is uniformly dispatched by the dispatching center (Fire Event) Subscriber registration to the dispatch center processing code .
╭─────────────╮ ╭───────────────╮ Fire Event ╭──────────────╮
│ │ Publish Event │ │───────────────>│ │
│ Publisher │────────────────>│ Event Channel │ │ Subscriber │
│ │ │ │<───────────────│ │
╰─────────────╯ ╰───────────────╯ Subscribe ╰──────────────╯
Copy code
class EventEmitter {
constructor(){
// Maintain events and subscription behavior Cache list ( Dispatching center )
this.events = {}
}
/**
* Register event listeners ( subscriber )
* @param {String} type Event type
* @param {Function} cb Callback function
*/
on(type,cb){
// Judge whether there is There is no create event type
if(!this.events[type]){
this.events[type] = []
}
this.events[type].push(cb);
}
/**
* Register once Automatically delete after calling
* @param {String} type Event type
* @param {Function} cb Callback function
*/
once(type,cb){
const _this = this;
function on () {
_this.off(type, on);
cb.apply(_this, arguments);
}
this.on(type, on);
}
/**
* Release events ( Publisher )
* @param {String} type Event type
* @param {...any} args parameter list , hold emit The parameters passed are assigned to the callback function
*/
emit(type, ...args){
// Loop triggers a registered event
if(this.events[type]){
this.events[type].forEach(element => {
element(...args);
});
}
}
/**
* Cancel event
* @param {String} type Event type
* @param Function} cb Callback function
*/
off(type,cb){
const evenItemData = this.events[type];
if(evenItemData){
// Determine whether the same event exists If there is, remove
evenItemData.forEach((item,i)=>{
if(item === cb){
evenItemData.splice(i, 1);
}
})
// If there is no content, the object is clear
if(this.events[type].length === 0 ){
delete this.events[type];
}
}
}
}
const eventEmitter = new EventEmitter();
const aFun = (a)=>{
console.log(" I am a click Method 1 "+a)
}
const bFun = (b)=>{
console.log(" I am a click Method 2 "+b)
}
const cFun = ()=>{
console.log(" I am a hhhh Register once ")
}
eventEmitter.on("click",aFun)
eventEmitter.on("click",bFun)
eventEmitter.once("hhhh",cFun)
eventEmitter.emit("click","aaaa");
eventEmitter.emit("hhhh");
eventEmitter.off("click",bFun)
eventEmitter.emit("click","bbbb");
eventEmitter.emit("hhhh"); // Cancelled Subscription not found
Copy code
DOM
In the event dispatchEvent
and addEventListener
The observer pattern is compared to the publish and subscribe pattern , More coupling , Usually used to achieve some responsive effects . In observer mode , There are only two subjects , They are the target objects Subject
, The observer Observer
.
Observer
To achieve update
Method , For the target object to call .update
Method can execute custom business code .Subject
It's also often called the observed or the subject , Its function is very single , It can be understood as , It only manages one kind of event .Subject
You need to maintain your own observer array observerList
, When you change yourself , By calling your own notify
Method , Notify each observer in turn to execute update
Method . ╭─────────────╮ Fire Event ╭──────────────╮
│ │─────────────>│ │
│ Subject │ │ Observer │
│ │<─────────────│ │
╰─────────────╯ Subscribe ╰──────────────╯
Copy code
// The observer
class Observer {
/**
* Constructors
* @param {Function} cb Callback function , When the target object notification is received
*/
constructor(cb) {
if (typeof cb === 'function') {
this.cb = cb
} else {
throw new Error('Observer The constructor must pass in the function type !')
}
}
/**
* Executed when notified by the target object
*/
update() {
this.cb()
}
}
// Target audience
class Subject {
constructor() {
// Maintain a list of observers
this.observerList = []
}
/**
* Add an observer
* @param {Observer} observer Observer example
*/
addObserver(observer) {
this.observerList.push(observer)
}
/**
* Notify all observers
*/
notify() {
this.observerList.forEach(observer => {
observer.update()
})
}
}
const observerCallback = function () {
console.log(' I was informed ')
}
const observer = new Observer(observerCallback)
const observer2 = new Observer(observerCallback)
const subject = new Subject();
subject.addObserver(observer);
subject.addObserver(observer2);
subject.notify();
Copy code
Subject
And the observer Observer
To implement the agreed member method . differences
:Personally think that , The observer model and the publish and subscribe model are essentially the same , The publish and subscribe model can be regarded as an advanced version of the observer model .