JavaScript中发布/订阅模式的理解
订阅发布模式的介绍
发布订阅模式,它定义了一种一对多的关系,可以使多个观察者对象对一个主题对象进行监听,当这个主题对象发生改变时,依赖的所有对象都会被通知到。
在生活中我们常常遇到这样一种情况,我们在使用新闻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('勇士'); /* 我订阅的球队是:湖人; 我订阅的球队是:湖人; 我订阅的球队是:勇士; 我订阅的球队是:勇士; */
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日
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
(码友推荐)2018-07-13 .NET及相关开发资讯速递
(码友推荐)2018-07-13 .NET及相关开发资讯速递: 1.Why Enterprises Are Turning to ASP.NET Core for Web Application Development2.What's New in .NET Core 2.13.Introducing TagHelpers in ASP.NET Core4.浅谈使用 Vue 构建前端 10w+ 代码量的单页面应用开发底层-博客-云栖社区-阿里云5.Bootstrap 4.1.2 - Bootstrap6.高效编写Dockerfile的几条准则7.我们习以为常的验证码,是个好设计吗?8.Why MySQL Stored Procedures, Functions and Triggers Are Bad For Performance9.10 JavaScript Animation Libraries to Follow in 201810.您有一份200套的免费UI素材包未接收,请打开文章领取11.如何选择UI 界面布局样式?来看丁香园设计师的总结!12.WPF 使用 WindowC...
- 下一篇
C#:使用MD5对用户密码加密与解密
原文: C#:使用MD5对用户密码加密与解密 C#中常涉及到对用户密码的加密于解密的算法,其中使用MD5加密是最常见的的实现方式。本文总结了通用的算法并结合了自己的一点小经验,分享给大家。 一.使用16位、32位、64位MD5方法对用户名加密 1)16位的MD5加密 /// <summary> /// 16位MD5加密 /// </summary> /// <param name="password"></param> /// <returns></returns> public static string MD5Encrypt16(string password) { var md5 = new MD5CryptoServiceProvider(); string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8); t2 = t2.Replace("-", ""); return t2;...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8安装Docker,最新的服务器搭配容器使用
- 设置Eclipse缩进为4个空格,增强代码规范
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS7安装Docker,走上虚拟化容器引擎之路