假如我们正在构建一个类似于 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. Chrome浏览器在Windows 和 Linux下的键盘快捷方式

    Windows 键盘快捷键 标签页和窗口快捷键 Ctrl+N 打开新窗口. Ctrl+T 打开新标签页. Ctrl+Shift+N 在隐身模式下打开新窗口. 按 Ctrl+O,然后选择文件. 通过 G ...

  2. 连接web端,mysql,返回乱码解决

    参考:http://yushan.iteye.com/blog/265019

  3. JAVA反射的使用之ResultSet的自动转换

    Hello,大家好,上篇文章我们说了下反射的基本情况和简单使用,那么本篇文章我们就使用反射写一个工具类.用来将数据库查询结果的ResultSet转换为指定类型的对象.使用反射来实现ResultSet内 ...

  4. Linux下golang开发环境搭建

    对于golang开发来说,Windows下可以用vscode或者liteide都不错,但是Linux下的开发也就只有vim了,所以怎么搞笑的利用vim进行golang开发呢? 参考官方推荐的一个插件: ...

  5. libevent源码分析:event_add、event_del

    event_add.event_del两个函数分别是使event生效和失效的,下面就来看一下两个函数的实现. event_add int event_add(struct event *ev, con ...

  6. Sqlserver 2008 error 40出现连接错误的解决方法

    说明(2017-5-25 15:00:16): 核心:把端口号改成1433 Sqlserver 2008 error 40出现连接错误的解决方法

  7. 随机颜色-js

    function ramColor() {            return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toSt ...

  8. golang深度获取子节点

    起因 需要在树形结构里获取子树,树形结构一般是存储一维数组,数组元素里存储子节点的指针 代码 package main import ( "errors" "fmt&qu ...

  9. tensorflow入门 (一)

    转载:作者:地球的外星人君链接:https://www.zhihu.com/question/49909565/answer/207609620来源:知乎著作权归作者所有.商业转载请联系作者获得授权, ...

  10. (转)spark日志配置

    一.第一部分 1.spark2.1与hadoop2.7.3集成,spark on yarn模式下,需要对hadoop的配置文件yarn-site.xml增加内容,如下: <property> ...