假如我们正在构建一个类似于 Google Docs 的应用程序,当用户按下一个按键时,需要做的事情有很多: 新字符显示到屏幕上;插入点向后移动;将本次动作加入到撤销的历史记录中; 保持与服务器同步;拼写错误检查;统计字数和页数等等。

按照传统的做法,假如我们监听 keypress 事件,并在一个处理中完成所有的任务,这想想都觉得可怕了。 那么有没有什么方法可以更好的解决这个问题,答案就是分布式事件。

PubSub 模式,是 Publish/Subscribe 的缩写,意为“发布/订阅”模式。

在实际使用中,我们应该也会接触到 PubSub 模式,例如 Nodejs 中的 EventEmitter、Backbone 中的事件模型、以及 jQuery 中的事件。 以 EventEmitter 为栗子,它提供了 addListener(event, listener),removeListener(event, listener),emit(event, [arg1], [arg2], [...]) 方法。

var emitter = new EventEmitter(),
fn1 = function(value) {
console.log('fn1:', value);
},
fn2 = function(value) {
console.log('fn2:', value);
}; emitter.addListener('message', fn1);
emitter.addListener('message', fn2);
emitter.emit('message', 'test1');
emitter.removeListener('message', fn2);
emitter.emit('message', 'test2'); //fn1: test1
//fn2: test1
//fn1: test2

当调用 emit 方法时,会触发所有监听的事件。

就像上面说的,PubSub 其实很简单,现在我们来实现属于我们自己的 PubSub 对象。

首先创建 PubSub 类,增加 handlers 变量用于保存事件列表:

function PubSub() {
this.handlers = {};
}

添加事件时,将监听器加到数组中:

PubSub.prototype.on = function(type, listener) {
if (!(type in this.handlers)) {
this.handlers[type] = [];
}
this.handlers[type].push(listener);
};

删除事件时,移除监听器:

PubSub.prototype.off = function(type, listener) {
var i,
position = -1,
list = this.handlers[type],
length = this.handlers[type].length; for (i = 0; i < length; i++) {
if (list[i] === listener) {
position = i;
break;
}
} if (position === -1) {
return;
} if (length === 1) {
delete this.handlers[type];
} else {
this.handlers[type].splice(position, 1);
}
};

触发事件,循环遍历并触发所有的事件:

PubSub.prototype.emit = function(type) {
var args = Array.prototype.slice.call(arguments, 1),
i,
list = this.handlers[type],
length = this.handlers[type].length; for (i = 0; i < length; i++) {
list[i].apply(this, args);
}
};

测试:

var pubsub = new PubSub(),
fn1 = function(value) {
console.log('fn1:', value);
},
fn2 = function(value) {
console.log('fn2:', value);
}; pubsub.on('message', fn1);
pubsub.on('message', fn2);
pubsub.emit('message', 'test1');
pubsub.off('message', fn2);
pubsub.emit('message', 'test2'); //fn1: test1
//fn2: test1
//fn1: test2

注:更多的实现请看 Nodejs 中的 events.js。

转自:http://www.wenzhixin.net.cn/2013/11/06/understand_pubsub

理解并实现PubSub模式的更多相关文章

  1. MVC+EF 理解和实现仓储模式和工作单元模式

    MVC+EF 理解和实现仓储模式和工作单元模式 原文:Understanding Repository and Unit of Work Pattern and Implementing Generi ...

  2. 深入理解JavaScript中创建对象模式的演变(原型)

    深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...

  3. ZeroMQ中PUB-SUB模式测试

    因为公司有需求,对程序模块之间通信效率有较高的需求.之前公司用的通信组件是ActiveMQ,根据网上公布的测试结果显示其效率比较低, 后来考虑准备在新的项目中开始使用ZeroMQ.看了几天发现用起来比 ...

  4. 理解 Android MVP 开发模式

    /***************************************************************************************** * 理解 Andr ...

  5. 简单理解设计模式——享元模式-线程池-任务(tesk)

    前面在写到多线程的文章的时候,一直想写一篇关于线程池等一系列的文章,做一下记录,本篇博客记录一下设计模式中享元模式的设计思想,以及使用享元模式的实现案例——线程池,以及线程池的简化版——任务(tesk ...

  6. ios--->OC中Protocol理解及在代理模式中的使用

    OC中Protocol理解及在代理模式中的使用 Protocol基本概念 Protocol翻译过来, 叫做"协议",其作用就是用来声明一些方法: Protocol(协议)的作用 定 ...

  7. 把酒言欢话聊天,基于Vue3.0+Tornado6.1+Redis发布订阅(pubsub)模式打造异步非阻塞(aioredis)实时(websocket)通信聊天系统

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_202 "表达欲"是人类成长史上的强大"源动力",恩格斯早就直截了当地指出,处在蒙昧时代即低 ...

  8. 飘逸的python - 理解打开文件的模式

    当我们用open()函数去打开文件的时候,有好几种打开的模式.   'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'->二 ...

  9. 我所理解的Android 启动模式

    首先,这是从 一个开源网站转载的,觉得写得不错,对我们之前理解的activity的启动模式是一个新的理解方式,并给出实际的应用场景. 任务栈是什么 任务栈Task,是一种用来放置Activity实例的 ...

随机推荐

  1. 部署ArcGIS JS API 离线包(Tomcat与IIS)

    http://www.cnblogs.com/ventlam/archive/2012/12/13/2815583.html

  2. Mac下终端(terminal)的一些快捷键

    Mac下终端(terminal)的一些快捷键 行首ctrl + a 行尾ctrl + e 两个终端窗口切换alt + 方向键 命令中,上一个单词esc + b (iterm2) 下一个单词esc + ...

  3. Ant编译android程序

    http://blog.csdn.net/xyz_lmn/article/details/7268582 这一篇主要做了创建android项目.update已存在项目.ant编译项目. 一,准备ant ...

  4. git 常用命令以及解决问题方法

    1. 创建分支: git branch test 2.切换分支: git checkout test 或切换为主分支 git checkout master 3.查看当前分支 git branch - ...

  5. 2. KNN和KdTree算法实现

    1. K近邻算法(KNN) 2. KNN和KdTree算法实现 1. 前言 KNN一直是一个机器学习入门需要接触的第一个算法,它有着简单,易懂,可操作性强的一些特点.今天我久带领大家先看看sklear ...

  6. axublog 1.05代码审计

    00x1 安装漏洞 install/cmsconfig.php function step4(){ $root=$_POST["root"]; $dbuser=$_POST[&qu ...

  7. mac OS X:[11]如何添加打印机

    苹果菜单中,单击下拉列表中的『系统偏好设置』: 或在Dock上,单击『系统偏好设置』图标. 2 在『系统偏好设置』窗口中,单击『打印机与扫描仪』图标. 3 在『打印机与扫描仪』窗口中,单击打印机框架下 ...

  8. redis详细配置文件

    redis 单机版自己指定配置 #修改为守护模式 daemonize yes #设置进程锁文件 pidfile /usr/local/redis/redis.pid #端口 port 6379 #客户 ...

  9. hive表增量抽取到oracle数据库的通用程序(一)

    hive表增量抽取到oracle数据库的通用程序(二) sqoop在export的时候 只能通过--export-dir参数来指定hdfs的路径.而目前的需求是需要将hive中某个表中的多个分区记录一 ...

  10. .net 定时启动任务

    .net winform程序,设置每天的零时启动,执行完后自动关闭. 系统计划启动: 如果要定时启动某个程序,可以通过“任务计划”来安排. 如果是XP系统,在开始 --> 所有程序 --> ...