发布-订阅模式在开发中的应用其实是很广泛的,比如大家都知道的 Vue,使用数据驱动模板的改变,将我们的双手从繁琐的 dom 操作中解放出来,稍微懂一些原理的同学们都知道,其双向数据绑定就是通过数据劫持、发布-订阅和 dom 模板编译实现的,就算不了解这个的同学,js 中的事件监听相信做前端开发的同学都写过;

其实事件监听就是一个订阅的操作,当某个事件触发的时候,对该事件监听时传入的 callback 就会被执行,这就是一个完整的发布的-订阅流程;接下来我们就来简单的写一下一个发布订阅器:

思路:

俗话说:磨刀不误砍柴工,在动手之前,缕清一下思路是有必要的,首先我们要明确这个发布订阅器的功能,其中包括

基本功能:

  • 可添加订阅者
  • 可触发消息通知某个订阅器执行其中的所有订阅者
  • 可删除指定订阅者

升级功能:

  • 可同时给多个订阅器添加订阅者
  • 可删除指定订阅器中的所有订阅者
  • 可指定同时删除多个订阅器或者直接清空所有订阅器
  • 可添加一次性订阅(该订阅者一旦被执行,就会在订阅器中移除)
  • 处理好 this 指向和实现链式调用
  • 添加错误判断和提醒机制

接下来我们就分两版上代码:

基础版

/*** 发布订阅器构造函数*/
var Publisher = (function() {function Publisher() {this._subs = {}; // 维护一个订阅器列表}/*** 添加订阅者* 若订阅者需要插入的订阅器不存在,则新创建一个* @param { string } type - 需要添加订阅者的订阅器名* @param { function } func - 订阅者*/Publisher.prototype.addSub = function(type, func) {if(!this._subs[type]) this._subs[type] = [];this._subs[type].push(func);};/*** 发布通知* 通知指定订阅器执行其中的每个订阅者* @param { string } type - 需要通知其发布消息的订阅器名*/Publisher.prototype.notify = function(type) {if(!this._subs[type]) return;var args = Array.prototype.slice.call(arguments, 1);this._subs[type].forEach(function(item) {item.apply(this, args);}, this);};/*** 删除订阅者* @param { string } type - 指定操作的订阅器名* @param { function } func - 指定需要删除的订阅者*/Publisher.prototype.destory = function(type, func) {this._subs[type].forEach(function(item, index, array) {(item === func) && array.splice(index, 1);}, this);};return Publisher;
}());
复制代码

基础版就如上面的代码,以最简单的方式实现一个发布订阅器的基本功能(能订阅,并能接收消息,还能指定删除)

升级版:

/*** 发布订阅器构造函数*/
var Publisher = (function() {function Publisher() {this._subs = {};}/*** 添加订阅者* 若订阅者需要插入的订阅器不存在,则新创建一个* 若传入的订阅器名为一个数组,则遍历数组内的每个订阅器添加订阅者* @param { string|Array<string> } type - 需要添加订阅者的订阅器名* @param { function } func - 订阅者* @returns { object } - 发布器实例,可实现链式调用*/Publisher.prototype.addSub = function(type, func) {if(Array.isArray(type)) {type.forEach(function(item) {this.addSub(item, func);}, this);} else {(this._subs[type] || (this._subs[type] = [])).push(func);}return this;};/*** 添加单次订阅* 当该订阅者在被通知执行一次之后会从订阅器中移除* @param { string|Array<string> } type - 需要添加订阅者的订阅器名* @param { function } func - 订阅者* @returns { object } - 发布器实例,可实现链式调用*/Publisher.prototype.once = function(type, func) {function onceAdd() {var args = Array.prototype.slice(arguments);this.destory(type, onceAdd);func.apply(this, args);}this.addSub(type, onceAdd);return this;};/*** 发布通知* 通知指定订阅器执行其中的每个订阅者* @param { string } type - 需要通知其发布消息的订阅器名* @returns { object } - 发布器实例,可实现链式调用*/Publisher.prototype.notify = function(type) {if(this._subs[type] === void 0) throw TypeError("Can't find the " + type + " event in the Publisher");var args = Array.prototype.slice.call(arguments, 1);this._subs[type].forEach(function(item) {item.apply(this, args);}, this);return this;};/*** 删除订阅器/订阅者* 若没有传入参数直接调用方法,将清空整个订阅器列表* 若只传入了订阅器类型参数,没有指定删除的订阅者,则删除该订阅器* @param { string|Array<string> } type - 指定操作的订阅器名,可用数组传入多个需要操作的订阅器名* @param { function } func - 指定需要删除的订阅者* @return { object } - 发布器实例,可实现链式调用*/Publisher.prototype.destory = function(type, func) {if(func && typeof func !== 'function') throw TypeError('The param "func" should be a function!');if(!arguments.length) {this._subs = {};return this;}if(Array.isArray(type)) {type.forEach(function(item) {this.destory(item, func);}, this);}if(!func) {delete this._subs[type];} else {this._subs[type].forEach(function(item, index, array) {(item === func) && array.splice(index, 1);}, this);}return this;};return Publisher;
}());
复制代码

以上就是一个简单的发布订阅器了,若有什么不足的地方,还望各位同学指正!

转载于:https://juejin.im/post/5b2602edf265da59aa2d879f

简单的写一个发布订阅器相关推荐

  1. 用vue简单写一个音乐播放器

    简单地写一个功能比较全的音乐播放器 前言 因为音乐播放器是一个很可能在项目遇到的东西,早写总比晚写好.趁没事先写个. 思路 一个音乐播放器该有的东西: 封面,歌名,专辑,作者 控制器(上一首,下一首, ...

  2. 怎样写一个拼写检查器-贝叶斯-python

    怎样写一个拼写检查器 Peter Norvig 翻译: Eric You XU 原版:http://norvig.com/spell-correct.html 翻译:http://blog.youxu ...

  3. 【ZT】怎样写一个拼写检查器

    这篇真的写的很棒,用心领会吧! 怎样写一个拼写检查器 Peter Norvig 翻译: Eric You XU 上个星期, 我的两个朋友 Dean 和 Bill 分别告诉我说他们对 Google 的快 ...

  4. 如何写一个拼写检查器—Peter Norvig 中文翻译:徐宥

    [转]如何写一个拼写检查器 本文原著:Peter Norvig  中文翻译:徐宥 上个星期, 我的两个朋友 Dean 和 Bill 分别告诉我说他们对 Google 的快速高质量的拼写检查工具感到惊奇 ...

  5. 怎样写一个拼写检查器

     怎样写一个拼写检查器 Peter Norvig 翻译: Eric You XU link:http://blog.youxu.info/spell-correct.html 上个星期, 我的两个 ...

  6. 用 Go 手写一个 JSON 序列化器

    用 Go 手写一个 JSON 序列化器 方案 实现 字符串转义 忽略类型 序列化器主体 数字和逻辑类型 字符串类型 数组类型 字典类型 自定义结构类型 指针类型 API 使用 安装 调用 测试 开源和 ...

  7. 用C++写一个文件分割器

    在成功将 mac 由 10.10 升级到 10.12 后,我发现除了新增一个并不怎么好用的 Siri 外,原来支持 NTFS 硬盘的驱动居然也成功失效了.我那块 500 GB 的东芝硬盘,虽不至于成砖 ...

  8. 用python写一个变声器,要求导入mp4或者mp3文件,将视频中的声音变成女声

    用python写一个变声器,要求导入mp4或者mp3文件,将视频中的声音变成女声 1.安装 pydub 库 2.然后可以使用以下代码导入 mp4 或 mp3 文件并将其变成女声: 1.安装 pydub ...

  9. 基于vue手写一个分屏器,通过鼠标控制屏幕宽度。

    基于vue手写一个分屏器,通过鼠标控制屏幕宽度. 先来看看实现效果: QQ录屏20220403095856 下面是实现代码: <template><section class=&qu ...

最新文章

  1. LeetCode简单题之最少操作使数组递增
  2. 看看Vector源码Java 9
  3. 全国默哀 网站首页都要变成灰色的简单解决办法
  4. paddle自定义weight初始参数(parameter)
  5. 借条的注意事项,上面不能有这3个字
  6. Codeforces Round #506 (Div. 3) - F. Multicolored Markers (思维)
  7. oracle装了客户端怎么登陆账号,分享Oracle 11G Client 客户端安装步骤(图文详解)...
  8. serialport通过usb通讯_IOT串口通讯-RS232/RS485
  9. net如何判断浏览器的类别
  10. android 仿ios timepicker,android:TimePicker仿照IOS時間選擇器,可自定義選擇器
  11. 随机二次元图片API源码
  12. 容器编排技术 -- Kubernetes入门概述
  13. Integer与int的区别
  14. AI 专利之争:小米超华为,国家电网才是大 Boss?
  15. 国产 Linux 发行版再添一员,界面不输苹果!太漂亮了。。
  16. 微信小程序客服介绍:如何设置小程序在线客服?
  17. 北航计算机学硕和专硕人数,2021考研报考人数公布!今年人数暴增了吗?
  18. 小新pro13睡眠后无法唤醒_小新air12、air13、air13pro睡眠后无法唤醒的调试方法
  19. 5G NR——传输信道、逻辑信道
  20. 李昌镐:苍老的青春(转载)

热门文章

  1. boost::histogram::make_profile用法的测试程序
  2. boost::hana::when用法的测试程序
  3. boost::gil::view_is_basic用法的测试程序
  4. boost::gil模块数字扩展中的 resample_pixels() 示例
  5. boost::fusion::pair用法的测试程序
  6. boost::contract模块没有宏实现base types的测试程序
  7. Boost::context模块fiber的斐波那契测试程序
  8. ITK:计算网格上的测地距离
  9. VTK:可视化算法之PineRootConnectivity
  10. VTK:可视化之KochSnowflake