JavaScript中发布/订阅模式的理解
发布日期:2021-09-10 08:03:59 浏览次数:10 分类:技术文章

本文共 2900 字,大约阅读时间需要 9 分钟。

订阅发布模式的介绍

发布订阅模式,它定义了一种一对多的关系,可以使多个观察者对象对一个主题对象进行监听,当这个主题对象发生改变时,依赖的所有对象都会被通知到。

在生活中我们常常遇到这样一种情况,我们在使用新闻APP看新闻的时候,每个人喜欢的新闻类型各不一样,比如我喜欢NBA,但是我们总不可能一天24小时在手机上一遍又一遍的刷新,我们就会去新闻频道中选择NBA专栏来收藏,当勇士或者湖人有最新消息,就会通知我们去观看。

当然从上面的场景中是一个典型的发布订阅模式,APP的NBA专栏属于发布者,像我一样广大爱好篮球的小伙伴梦就属于订阅者,当一有最新的消息,它们就会发布给我们。

实际用途

1.在jquery中很多地方都有发布订阅的踪迹,例如事件中on和trigger中封装的方法。

2.尤大大的Vue,中子父组件通信使用的emit()和on()方法,使得组件得到解耦,开发更加高效。

如何实现订阅发布模式

1、首先想好谁是发布者(比如上边的APP的NBA专栏就是发布者);

2、然后给发布者添加一个缓存列表,用于存放回调函数来通知订阅者(比如上面的我们球迷爱好者收藏了NBA专栏,相当于向发布者注入了通知我们的函数);

3、最后就是发布消息,发布者遍历这个缓存列表,依次触发订阅的函数。

表捉急,端起小板凳,先看一下这个简单的发布订阅模式:

let NBAcol={};//自定义一个NBA专栏对象NBAcol.list=[];// 这里放一个列表用来缓存订阅者的回调函数NBAcol.on=function(fun){    this.list.push(fun); //把fn先存到列表中};//发布事件NBAcol.emit=function(){    this.list.forEach(cb => {        cb.apply(this, arguments);    });// 当发布的时候再把列表里存的函数依次执行};//小明的订阅NBA专栏NBAcol.on(function(team){    console.log("我订阅的球队是:"+team)})//小李的订阅NBA专栏NBAcol.on(function(team){    console.log("我订阅的球队是:"+team)})NBAcol.emit('湖人');NBAcol.emit('勇士');/*我订阅的球队是:湖人;我订阅的球队是:湖人;我订阅的球队是:勇士;我订阅的球队是:勇士;*/
上面就实现了一个简单的订阅发布模式,不过从打印结果来看,有些尴尬,因为其实,小明只想订阅湖人,小李要订阅勇士。可是专栏都给他们推送了,显然不太合理。之所以出现这种情况是因为在执行on方法的时候将订阅函数列表中的函数依次都执行了。所以我们要对代码进行改造,我们可以先增加一个key,使订阅者只订阅自己感兴趣的消息。
let NBAcol={};//自定义一个NBA专栏对象NBAcol.list={};// 这里放一个列表用来缓存订阅者的回调函数NBAcol.on=function(key,fun){     // 如果还没有订阅过此类消息,给该类消息创建一个缓存列表    if(!this.list[key]){        this.list[key]=[];    }    this.list[key].push(fun); //把fn先存到列表中};//发布事件NBAcol.emit=function(){    let key=Array.prototype.shift.call(arguments);// 取出消息类型名称    let funs=this.list[key];//匹配对应的回调函数的结合    if(!funs||funs.length===0){//如果没有订阅过消息,则return;        return;    };    funs.forEach(fun => {        fun.apply(this, arguments);    });// 当发布的时候再把列表里存的函数依次执行};//小明的订阅NBA专栏NBAcol.on('xiaomin',function(team){    console.log("我订阅的球队是:"+team)})//小李的订阅NBA专栏NBAcol.on('xiaoli',function(team){    console.log("我订阅的球队是:"+team)})NBAcol.emit('xiaomin','湖人');NBAcol.emit('xiaoli','勇士');/*我订阅的球队是:湖人;我订阅的球队是:勇士;*/

这样子就可以啦,这个订阅发布的核心功能已经体现了。

如何取消事件的订阅

比如上面的列子,假如我们订阅了很多东西,不喜欢的时候我们要取消订阅,该怎么办呢?看如下代码:

NBAcol.remove=function(key, fun) {        // 这回我们加入了取消订阅的方法        let funs = this.list[key];        // 如果缓存列表中没有函数,返回false        if (!funs) return false;        // 如果没有传对应函数的话        // 就会将key值对应缓存列表中的函数都清空掉        if (!fun) {            funs && (funs.length = 0);        } else {            // 遍历缓存列表,看看传入的fun与哪个函数相同            // 如果相同就直接从缓存列表中删掉即可            funs.forEach((cb, i) => {                if (cb === fun) {                    funs.splice(i, 1);                }            });        }    }        // 取消dog方法的订阅    NBAcol.remove('xiaoli',function(team){       console.log("我订阅的球队是:"+team)    });

这样就可以取消订阅啦,但是实际的开源代码中,封装远比这要复杂,比如要考虑订阅数量,还有多模块订阅的封装等等,所以在这里我们还得在实际的业务模块中详细考虑。

发布订阅模式的缺点:

当然一个任何一个东西都是有两面性的,同样发布订阅模式存在以下问题:

1、创建订阅者需要消耗一定的时间和内存。

2、虽然可以弱化对象之间的联系,如果过度使用的话,反而使代码不好理解及代码不好维护等等。

原文发布时间为:2018年06月24日
原文作者:viyoung
本文来源: 
如需转载请联系原作者

转载地址:https://blog.csdn.net/weixin_34378767/article/details/89694432 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:G6 2.0 发布稿 -- 裂变与聚变
下一篇:Github上如何查看不同的license的更多信息

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月18日 11时30分35秒