PubSub的一种实现

时间:2022-12-31 23:59:13

今天在浏览JavaScript事件时,复习了下Dean Edward大神的addEvent。突然觉得可以基于他的思路实现一个结构更好的PubSub。

思路也很简单,就是要维护一个类似如下的一个仓库结构:

/*
{
'sayHello': {
0: fn0,
1: fn1,
//... },
'sayGoodBye': {
0: fnn,
//...
},
//...
}*/

下面是我的实现代码:

(function(exports) {
var PubSub = exports.PubSub || {}; //在PubSub对象上增加静态域PubSubCache,用于保存subscribe相关数据 /**
* PubSub.PubSubCache仓库结构
* {
* 'sayHello': {
* 0: fn0,
* 1:fn1,
* //..。
* },
* 'sayGoodBye': {
* //...
* }
* }
*
*/
PubSub.PubSubCache = PubSub.PubSubCache || {$uid: 0}; //PubSub有4个静态方法:subscribe, subscribeOne, unsubscribe, publish
//PubSub不会与DOM元素有关系。这样publish也只能手动去触发了
PubSub.subscribe = function(type, handler) {
var cache = this.PubSubCache[type] || (this.PubSubCache[type] = {});
handler.$uid = handler.$uid || this.PubSubCache.$uid++; //把回调放入仓库中
cache[handler.$uid] = handler;
}; PubSub.unsubscribe = function(type, handler) {
var counter = 0,$type, cache = this.PubSubCache[type]; if(arguments.length === 1) {
//直接删除此种类型的订阅对象
if(!cache) return true;
return !!this.PubSubCache[type] && (delete this.PubSubCache[type]);
} else if(arguments.length === 2) {
!!this.PubSubCache[type] && (delete this.PubSubCache[type][handler.$uid]);
} //PubSubCahe仓库中某类型订阅为空,则要删除这个订阅对象
for($type in cache) {
counter++;
} return !counter && (delete this.PubSubCache[type]);
}; PubSub.publish = function(type) {
var cache = this.PubSubCache[type], key, oneFlag, tmp, context, args = [].slice.call(arguments); if(!cache) return; if(args.length === 1) {
context = exports;
} else {
context = args[1];
} //执行回调
for(key in cache) {
tmp = cache[key];
//在发布消息时可以指定回调函数的上下文,同时还可以传入参数
cache[key].apply(context, args.slice(1));
tmp.one && this.unsubscribe(type, tmp);
}
}; PubSub.subscribeOne = function(type, handler) {
this.subscribe(type, handler);
//给函数加一个只执行一次的标志
handler.one = true;
}; exports.PubSub = PubSub;
})(window);
 

下面是测试代码:

var data = {name: 'haha', age:18};

var handler2 = function(data) {
console.log('say.hello excuted! 2');
console.log(this.name);
}; //订阅say.hello消息
PubSub.subscribe('say.hello', function(data) {
console.log('say.hello excuted! 1');
}); //第二次订阅say.hello消息
PubSub.subscribe('say.hello', handler2); //第三次订阅say.hello消息
PubSub.subscribe('say.hello', function(data) {
console.log('say.hello excuted! 3');
console.log(this.age);
}); //第四次增加一个只会执行一次的say.hello消息订阅
PubSub.subscribeOne('say.hello', function(data) {
console.log('say.hello excuted! one');
}); /**
* 发布say.hello消息类型
* 输出:
* say.hello excuted! 1
* say.hello excuted! 2
* haha
* say.hello excuted! 3
* 18
* say.hello excuted! one
*/ PubSub.publish('say.hello', data); //取消第二次订阅的say.hello类型
PubSub.unsubscribe('say.hello', handler2); /**
* 发布say.hello消息类型
* 输出:
* say.hello excuted! 1
* say.hello excuted! 3
* 18
*/ console.log('--------------------------------')
PubSub.publish('say.hello', data); /**
* 再次发布say.hello消息,不过这次除了传入执行上下文外,还要传入参数
* 输出:
* say.hello excuted! 1
* say.hello excuted! 3
* 18
* say.hello excuted! has deliverd args
* args123
*/ PubSub.subscribe('say.hello', function(data, args) {
console.log('say.hello excuted! has deliverd args');
console.log(args);
}); console.log('--------------------------------')
PubSub.publish('say.hello', data, 'args123');

小结:

全局的PubSub对象有四个方法:

1. subscribe(type, handler) :增加一种类型的消息订阅。类似jQuery的bind();

2. subscribeOne(type, handler):增加一种回调只会执行一次的消息订阅,类似jQuery的one()

3. unsubscribe(type, [handler]): 如果只传type,会删除所有的type消息订阅;传入了回调函数,则只删除那一个回调。类似jQuery的unbind()

4. publish(type):执行订阅。类似jQuery的trigger();

当然上面的功能Cowboy大神只用了只行代码就实现了(基于jQuery):

(function($) {
//得到一个jQuery对象,以便使用其方法
var o = $({}); //为jQuery对象增加静态的方法
$.subscribe = function() {
o.bind.apply(o, arguments);
}; $.unsubscribe = function() {
o.unbind.apply(o, arguments);
}; $.publish = function() {
o.trigger.apply(o, arguments);
} })(jQuery);

PubSub的一种实现的更多相关文章

  1. GCP消息队列Pubsub详解,简单好用还不用自己运维

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 GCP的Pubsub是一种异步消息传递服务,可将生产事件的服务与处理事件的服务隔离开.消息队列的作用就不多作介绍 ...

  2. Redis info参数总结(转)

    Redis官网对 info 已经讲解的比较清楚的,参考文档 . 可以看到,info的输出结果是分几块的,有Servers.Clients.Memory等等,通过info后面接这些参数,可以指定输出某一 ...

  3. 关于Redis info的参数总结

    Redis官网对 info 已经讲解的比较清楚的,参考文档 .可以看到,info的输出结果是分几块的,有Servers.Clients.Memory等等,通过info后面接这些参数,可以指定输出某一块 ...

  4. (转)基于即时通信和LBS技术的位置感知服务(一):提出问题及解决方案

    一.前言.提出问题 公司最近举行2011年度创新设计大赛,快年底了正打算写写2010年以来Android开发的心得与经验,正好同事出了个点子:假如A和B两个人分别在不同的地点,能不能实现这样的功能,让 ...

  5. redis info命令结果释疑

    redis的性能数据这块用 info 命令就可以获取的比较全面了,下面是对info信息返回值的解释: # 参考:http://redis.io/commands/info # # # Server r ...

  6. vue的组件详解

    什么是组件 组件(Component)是 Vue.js 最强大的功能之一.(好比电脑中的每一个元件(键盘,鼠标,CPU),它是一个具有独立的逻辑和功能或界面,同时又能根据规定的接口规则进行互相融合,变 ...

  7. Redis info参数总结

    可以看到,info的输出结果是分几块的,有Servers.Clients.Memory等等,通过info后面接这些参数,可以指定输出某一块数据. 下面是针对info的输出在旁边注释了,因为对Redis ...

  8. JMS学习之理论基础

    本文代码使用ActiveMq5.6 一.什么是JMS JMS(Java Message Service,Java消息服务)是一组Java应用程序接口(Java API),它提供创建.发送.接收.读取消 ...

  9. 组件通信之全局事件总线 & 消息订阅发布

    全局事件总线 介绍 一种组件间通信的方式,适用于任意组件间通信. 在使用全局事件总线之前需要一些知识准备 所有组件实例的原型对象的原型对象就是 Vue 的原型对象,即VueComponent.prot ...

随机推荐

  1. Ognl表达式基本原理和使用方法

    Ognl表达式基本原理和使用方法 1.Ognl表达式语言 1.1.概述 OGNL表达式 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个 ...

  2. 【腾讯Bugly干货分享】OCS——史上最疯狂的iOS动态化方案

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/zctwM2Wf8c6_sxT_0yZvXg 导语 在 ...

  3. //给定N个整数序列{A1,A2,A3...An},求函数f(i,j)=(k=i~j)Ak的求和

    //给定N个整数序列{A1,A2,A3...An},求函数f(i,j)=(k=i~j)Ak的求和 # include<stdio.h> void main() { ,sum1; ]={,- ...

  4. jquery 实现邮箱输入自动提示功能:(一)

    记得去年做某个项目的时候,用到了邮箱输入自动提示功能,于是网上搜了一下,发现了这个写得不错,现在回想起来,转载一下,方便查阅. 邮箱的广泛使用得益于它的免费,因此很多网站在注册的时候都会直接使用邮箱作 ...

  5. java学习之协调同步的线程

    当一个线程使用的同步方法中用到某个变量,而此变量有需要其他线程修改后才能符合本线程的需要, 那么可以在同步方法中使用wait(),wait方法可以中断线程的执行,使本线程等待,暂时让出CPU的使用权, ...

  6. Linux下面如何安装Django

    首先你需要肯定你的机子上装了Python 现在ubuntu已经自带,所以不必操心 当然你可以在你的机子下测试一下,只需在 terminal 下输入 python 如果出现下面的界面就说明你机子已经装了 ...

  7. RFID第二次作业

    1.简述智能卡的发展,以及射频电子标签在其中所处的位置. 智能卡(Smart Card)又称为集成电路卡(IC卡),内部带有微处理器和存储单元等部件. 射频电子标签是一种非接触式的IC卡,是后期发展起 ...

  8. 发布ASP&period;NET网站到IIS

    1.         在Web项目中点击发布网站,如图1所示 图1 2.         选择要发布的路径——>“确定”,如果项目显示发布成功就可以了.如图2所示 图2 3.         打 ...

  9. linux字体安装

    Google查了一下,果然Windows下的ttf字体与GNOME是兼容的!我立即确定了我的方案——使用Windows下的“微软雅黑”体作为桌面和应用程序的默认字体! 1. 首先获得一套“微软雅黑”字 ...

  10. Linux Server release 7&period;3 更换阿里网络yum源

    查看当前系统下的yum源 [root@localhost ~]# rpm -qa |grep yum yum-3.4.3-150.el7.noarch yum-utils-1.1.31-40.el7. ...