zoukankan      html  css  js  c++  java
  • javascript 设计模式 发布订阅模式

    发布/订阅模式(Pub/Sub)是一种消息模式,它有两个参与者:发布者和订阅者。发布者向某个信道发布
    一条消息,订阅者绑定这个信道,当有消息发布至信道时就会接收到一个通知。最重要的一点是,发布者和
    订阅者是完全解耦的,彼此并不知晓对方的存在。两者仅仅共享一个信道名称。

    这种模式在js里面有这天然的优势,因为js本身就是事件驱动型语言。比如,页面上有一个button,
    你点击一下就会触发上面的click事件,而此时有一部分程序正在监听这个事件,随之触发相关的处理程序。

    事实上,我们也早就熟悉这个模式了,只是不知道这叫什么(订阅发布模式 又名 观察者模式).
    这个模式最大的一个好处就在于,能够解耦回调函数,让你的程序看起来更美观(虽然现在有Promise和

    Deferred帮忙,但是不彻底)。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>发布订阅模式</title>
    </head>
    <body>
    <script>
        var pubsub = (function(){
            var q = {}, topics = {}, subUid = -1;
            //发布消息
            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;
            };
            //订阅事件
            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;
            //取消订阅就不写了,遍历topics,然后通过保存前面返回token,删除指定元素
        })();
        //触发的事件
        var logmsg = function(topics, data) {
            console.log("logging:" + topics + ":" + data);
        }
        //监听指定的消息'msgName'
        var sub = pubsub.subscribe('msgName', logmsg);
        //发布消息'msgName'
        pubsub.publish('msgName', 'hello world');
        //发布无人监听的消息'msgName1'
        pubsub.publish('anotherMsgName', 'me too!');
    </script>
    </body>




    功能完善的发布订阅模式:

    <!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]) {
                    //如果有就放一个新的
                    this._events[eventName].push(callback);
                } else {
                    //如果没有就创建一个数组
                    this._events[eventName] = [callback];
                }
            },
            emit: function (eventName, caller, args) {
                if (this._events[eventName]) { //循环一次执行
                    this._events[eventName].forEach(function(item) {
                        item.apply(caller, args)
                    });                
                }          
            },
            removeListener: function (eventName, callback) {
                if (this._events[eventName]) {
                    //当前数组和传递过来的callback相等则移除掉
                    //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() {
                    //在one函数运行原来的函数,只有将one清空
                    callback.apply(this, arguments);
                    //先绑定 执行后再删除
                    that.removeListener(eventName, one);
                }
                this.on(eventName, one);
                //此时emit触发会执行此函数,会给这个函数传递rest参数
            }        
        }
        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>  

    使用es6实现:

    <!DOCTYPE html>  
    <html>  
    <head>  
        <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>  
    </head>  
    <body>   
    <script> 
    
    //发布订阅模式
    class EventEmiter{
      constructor(){
        //维护一个对象
        this._events={
     
        }
      }
      on(eventName,callback){
        if( this._events[eventName]){
          //如果有就放一个新的
          this._events[eventName].push(callback);
        }else{
          //如果没有就创建一个数组
          this._events[eventName]=[callback]
        }
      }
      emit(eventName,...rest){
        if(this._events[eventName]){ //循环一次执行
          this._events[eventName].forEach((item)=>{
            item.apply(this,rest)
          });
        }
      }
      removeListener(eventName,callback){
        if(this._events[eventName]){
          //当前数组和传递过来的callback相等则移除掉
          this._events[eventName]=
            this._events[eventName].filter(item=>item!==callback);
        }
      }
      once(eventName,callback){
        function one(){
          //在one函数运行原来的函数,只有将one清空
          callback.apply(this,arguments);
          //先绑定 执行后再删除
          this.removeListener(eventName,one);
        }
        this.on(eventName,one);
          //此时emit触发会执行此函数,会给这个函数传递rest参数
      }
    }
    class Man extends EventEmiter{}
    let man=new Man()
    function findGirl() {
      console.log('找新的女朋友')
    }
    function saveMoney() {
      console.log('省钱')
    }
    man.once('失恋',findGirl);
    //man.on('失恋',findGirl) //失恋 ,绑定一个函数方法
    man.on('失恋',saveMoney)//失恋 ,绑定一个函数方法
    man.removeListener('失恋',saveMoney); //移除一个函数方法
    man.emit('失恋');
    //绑定一次,触发多次,也只执行一次。触发后一次将数组中的哪一项删除掉下次触发就不会执行
    </script>  
    </body>  
    </html>  



  • 相关阅读:
    Java核心技术第四章----对象与类重难点总结
    Java核心技术第三章----Java的基本程序设计结构重难点总结
    IDEA Invalid bound statement (not found)
    安利一个免费下载VIP文档神器
    灵魂拷问--你是什么垃圾?垃圾分类找人工智障!!!让你再也不拍大妈的灵魂拷问
    JavaWeb无框架,借助反射采用精巧设计模式实现放微信PC聊天页面
    JavaWeb购物车
    来自大专生的些许感悟
    2021 第二轮省队集训 Day5
    2021 第二轮省队集训 Day2
  • 原文地址:https://www.cnblogs.com/xutongbao/p/9924958.html
Copyright © 2011-2022 走看看