发布-订阅模式

本文深入解析发布订阅模式,展示如何通过一个独立对象实现该模式,包括事件监听、触发及取消订阅功能。并通过真实网站登录场景示例,说明该模式如何促进模块间解耦,提高代码的可维护性和扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

将发布订阅的功能提取出来,放在一个单独的对象中

var event={
    clientList:{},
    listen:function(key,fn){
        if(!this.clientList[key]){
            this.clientList[key]=[];
        }
        this.clientList[key].push(fn);
    },
    trigger:function(){
        var key=Array.prototype.shift.call(arguments),
            fns=this.clientList[key];
        if(!fns||fns.length===0){
            return false;
        }
        for (var i = 0,fn;fn = fns[i++];) {
            fn.apply(this,arguments);
        }
    },
};

var installEvent = function(obj){
    for(var i in event){
        obj[i] = event[i];
    }
}

var salesOffices = {};
installEvent(salesOffices);

salesOffices.listen('squareMeter88',function(price){
    console.log("价格="+price);
});
salesOffices.listen('squareMeter110',function(price){
    console.log("价格="+price);
});

salesOffices.trigger('squareMeter88',20000);
salesOffices.trigger('squareMeter110',30000);

取消订阅事件

//取消订阅事件
event.remove=function(key,fn){
    var fns=this.clientList[key];
    if(!fns){
        return false;
    }
    if(!fn){
        fns&&(fns.length=0);
    }else{
        for (var l = fns.length-1; l>=0; l--) {
            var _fn = fns[l];
            if(_fn === fn){
                fns.splice(l,1);
            }
        }
    }
}

应用-真实的例子-网站登录

假如我们正在开发一个商城网站,网站中有header头部、nav导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件,就是必须先使用ajax异步请求获取用户的登录信息。比如用户的名字和头像要显示在header模块中,而这两个字段都来自用户登录后返回的信息。

至于ajax请求什么时候能成功返回用户信息,没有办法确定。

对用户信息感兴趣的业务模块将自行订阅登录成功的消息事件。当登陆成功时,登录模块只需要发布登录成功的消息,而业务方接受消息后,就会开始进行各自的业务处理,登录模块并不关心业务方要做什么,也不需要了解他们的内部细节。改善后的代码如下:

$.ajax('http://xxx.com?login',function() {    //登录成功
    login.trigger('loginSucc',data);        //发布登录成功的消息
});
//各模块监听成功的消息
var header=(function(){
    login.listen('loginSucc',function(data){    //header模块
        header.setAvatar(data.avatar);
    });
    return {
        setAvatar:function(data){
            console.log('设置header模块的头像');
        }
    }
})();
var nav=(function(){     //nav模块
    login.listen('loginSucc',function(data){
        nav.setAvatar(data.avatar);
    });
    return {
        setAvatar:function(avatar){
            console.log('设置nav模块的头像');
        }
    }
})();

如上所述,我们可以随时把setAvatar的方法名改成setTouxiang。如果有一天在登录完成之后,又增加一个刷新收货地址列表的行为,那么只要在收货地址模块里加上监听消息的方法即可,而这可以让开发该模块的同事自己完成,你作为登录模块的开发者,永远不用再关心这些行为了。

var address=(function(){
    login.listen('loginSucc',function(data){
        address.refresh(obj);
    });
    return {
        refresh:function(avatar){
            console.log('刷新收货地址列表');
        }
    }
})();

本人学习整理,非原创

 

 

转载于:https://my.oschina.net/u/2936129/blog/755392

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值