The Publish/subscribe pattern (Pub/Sub) is a messaging pattern that has two participants: publishers and subscribers. A publisher publishes a message to a channel, and subscribers bind to the channel and receive a notification when a message is published to the channel. Most importantly, publishers and subscribers are completely decoupled, unaware of each other’s existence. Both share only one channel name. This pattern has a natural advantage in JS because JS is an event-driven language. For example, if you have a button on the page, clicking on it will trigger the click event, and a part of the program is listening for that event, which will trigger the relevant handler. In fact, we are already familiar with this pattern. We just don’t know what it is called (subscription publishing aka observer pattern). One of the biggest benefits of this pattern is that it decouples callback functions, making your program look better (although now there are promises and \)

Deferred helps, but not completely).

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Publish and subscribe model</title>
</head>
<body>
<script>
    var pubsub = (function(){
        var q = {}, topics = {}, subUid = -1;
        // Publish the message
        q.publish = function(topic, args) {
            if(! topics[topic]) {return;
            }
            var subs = topics[topic], len = subs.length;
            while(len--) {
                subs[len].func(topic, args);
            }
            return this;
        };
        // Subscribe to events
        q.subscribe = function(topic, func) {
            topics[topic] = topics[topic] ? topics[topic] : [];
            var token = (++subUid).toString();
            topics[topic].push({
                token : token,
                func : func
            });
            return token;
        };
        return q;
        // Unsubscribe and stop writing, iterate over topics, and then delete the specified element by saving the token in front of it}) ();// Trigger the event
    var logmsg = function(topics, data) {
        console.log("logging:" + topics + ":" + data);
    }
    // listen for the specified message 'msgName'
    var sub = pubsub.subscribe('msgName', logmsg);
    // Publish message 'msgName'
    pubsub.publish('msgName'.'hello world');
    // Publish unlistened message 'msgName1'
    pubsub.publish('anotherMsgName'.'me too! ');
</script>
</body>
Copy the code


\

\

\

Fully functional publish and subscribe model: \

<! DOCTYPE html><html>  
<head>  
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>  
</head>  
<body>   
<script> 

var $EventEmiter = (function () {
    function $EventEmiter () {
        this._events = {
        }
    }
    $EventEmiter.prototype = {
        on: function (eventName, callback) {
            if (this._events[eventName]) {
                // If there is one, put a new one
                this._events[eventName].push(callback);
            } else {
                // If not, create an array
                this._events[eventName] = [callback]; }},emit: function (eventName, caller, args) {
            if (this._events[eventName]) { // Execute the loop once
                this._events[eventName].forEach(function(item) { item.apply(caller, args) }); }},removeListener: function (eventName, callback) {
            if (this._events[eventName]) {
                // If the current array is equal to the passed callback, it is removed
                //this._events[eventName] = this._events[eventName].filter(item=>item! ==callback);
                var temp = [];
                for (var i = 0; i < this._events[eventName].length; i++) {
                    if (this._events[eventName][i] ! == callback) { temp.push(this._events[eventName][i]); }}this._events[eventName] = temp; }},removeListenerByEventName: function (eventName) {
            if (this._events[eventName]) {
                this._events[eventName] = []; }},once: function(eventName, callback) {
            var that = this;
            function one() {
                // Run the original function in the one function, only one empty
                callback.apply(this.arguments);
                // Bind is executed before deletion
                that.removeListener(eventName, one);
            }
            this.on(eventName, one);
            // The emit trigger will execute the function, passing the rest argument to the function}}return$EventEmiter; }) ();var EventEmiter = new $EventEmiter();

var msgName = function(data) {  
    console.log("msgName:" + data);  
}  
var sub = EventEmiter.on('msgName', msgName);  
var msgNames = function(data) {  
    console.log("msgNames:" + data);  
}  
var sub = EventEmiter.on('msgName', msgNames); 
EventEmiter.emit('msgName'.this['hello world']);    
EventEmiter.emit('msgName'.this['hello world2']);  
EventEmiter.removeListener('msgName', msgName);
EventEmiter.emit('msgName'.this['hello world3']);  
EventEmiter.removeListenerByEventName('msgName');
EventEmiter.emit('msgName'.this['hello world4']);  
EventEmiter.emit('msgName'.this['hello world5']);  

var msgName2 = function(data) {  
    console.log("msgName2:" + ":" + data);  
}  
var sub = EventEmiter.once('msgName2', msgName2);  
EventEmiter.emit('msgName2'.this['hello world']);    
EventEmiter.emit('msgName2'.this['hello world2']);

EventEmiter.emit('anotherMsgName'.this['me too! ']);  

</script>  
</body>  
</html>  
Copy the code

\

Using ES6 implementation: \

<! DOCTYPE html><html>  
<head>  
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>  
</head>  
<body>   
<script> 

// Publish subscribe mode
class EventEmiter{
  constructor(){
    // Maintain an object
    this._events={
 
    }
  }
  on(eventName,callback){
    if( this._events[eventName]){
      // If there is one, put a new one
      this._events[eventName].push(callback);
    }else{
      // If not, create an array
      this._events[eventName]=[callback]
    }
  }
  emit(eventName,... rest){
    if(this._events[eventName]){ // Execute the loop once
      this._events[eventName].forEach((item) = >{
        item.apply(this,rest) }); }}removeListener(eventName,callback){
    if(this._events[eventName]){
      // If the current array is equal to the passed callback, it is removed
      this._events[eventName]=
        this._events[eventName].filter(item= >item!==callback);
    }
  }
  once(eventName,callback){
    function one(){
      // Run the original function in the one function, only one empty
      callback.apply(this.arguments);
      // Bind is executed before deletion
      this.removeListener(eventName,one);
    }
    this.on(eventName,one);
      // The emit trigger will execute the function, passing the rest argument to the function}}class Man extends EventEmiter{}
let man=new Man()
function findGirl() {
  console.log('Find a new girlfriend')}function saveMoney() {
  console.log('save money')
}
man.once('love',findGirl);
//man.on(' lovelorn ',findGirl) // Lovelorn, bind a function method
man.on('love',saveMoney)// bind a function method
man.removeListener('love',saveMoney); // Remove a function method
man.emit('love');
// Bind once, trigger multiple times, execute only once. Which item in the array is deleted once triggered will not be executed the next time triggered
</script>  
</body>  
</html>  
Copy the code

\

\

\