【JavaScript】让事件支持先发布后订阅
之前写过一个的事件管理器,就是普通的先订阅后发布模式。但实际场景中我们需要做到后订阅的也能收到发布的消息。比如我们关注微信公众号,还是能看到历史消息的。类似于qq离线消息,我先发给你,你登录了就能收到了。就是确保订阅该事件的方法都能被执行。
var eventManger = {
cached: {},
handlers: {},
//类型,绑定事件
addHandler: function (type, handler) {
if (typeof handler !== "function") return; if (typeof this.handlers[type] == "undefined") {
this.handlers[type] = [];
}
this.handlers[type].push(handler); if (this.cached[type] instanceof Array) {
//说明有缓存的 可以执行
handler.apply(null, this.cached[type]);
}
},
removeHandler: function (type, handler) {
var events = this.handlers[type];
for (var i = 0, len = events.length; i < len; i++) {
if (events[i] == handler) {
events.splice(i, 1);
break;
}
}
},
trigger: function (type) {
//如果有订阅的事件,这个时候就触发了
if (this.handlers[type] instanceof Array) {
var handlers = this.handlers[type];
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0, len = handlers.length; i < len; i++) {
handlers[i].apply(null, args);
}
}
//默认缓存
this.cached[type] = Array.prototype.slice.call(arguments, 1);
}
};
其实就是增加了几行代码。缓存下最后一次触发的时的参数。 然后在addhandle的时候进行判断,如果订阅的时候已经有缓存的参数了,说明该方法可以执行了。
eventManger.addHandler("test", function (res) {
console.log("先订阅,后发布1", res);
}) eventManger.trigger("test", 2); eventManger.addHandler("test", function (res) {
console.log("先发布,后订阅2", res);
}) eventManger.addHandler("test", function (res) {
console.log("先发布,后订阅3", res);
})
我实际的场景是这样的A事件触发之后,才能执行B方法。但B方法需要在C方法完成之后。也就是B依赖于A和C的完成。且A几乎每次都会很快触发,当然可以设两个个开关变量和一个代理函数,等两个事件都完成之后再do B。代码如下:
var aReady = false;
var cReady = false;
eventManger.addHandler("A", function () {
aReady = true;
console.log("do A");
proxyC();
}); eventManger.trigger("A", 2); function doB() {
console.log("do B");
//实际B中的方法需要在A事件成功之后才能执行
} function doC() {
console.log("do C");
cReady = true;
proxyC();
} function proxyC() {
aReady && cReady && doB();
}
doC();
这样功能是实现了,但是可读性差了,而且事件订阅必须要对位置,如果在trigger之前,doB就永远执行不了,而且代码上多了两个变量和一个方法,最傻的是用一个变量加setTimeout去判断状态,这就可能陷入死循环。
var aReady = false;
eventManger.addHandler("A", function () {
aReady = true;
console.log("do A");
}); function doB() {
console.log("do B");
//实际B中的方法需要在A事件成功之后才能执行
} function doC() {
console.log("do C");
if (!aReady) {
console.log("wating...");
setTimeout(doC, 50);
return;
}
doB();
} doC(); eventManger.trigger("A", 2);//模拟A事件触发迟
这种办法最不可取吧。因为外部事件可能挂掉,这儿就走不出去了。等于是挖了个坑。但如果事件支持先发布,后订阅,问题就简单了:
eventManger.trigger("A", 2); function doB() {
console.log("do B");
//实际B中的方法需要在A事件成功之后才能执行
} function doC() {
console.log("do c");
eventManger.addHandler("A", function () {
console.log("do a");
doB();
});
}
doC();
这样就清晰了很多。事件订阅也不必那么在意调用的位置了。以上只是记住最近的一次的调用参数,可以用于后订阅的事件触发。这适合一次性事件(一个周期只会触发一次的事件)。如果是像推送消息的事件,会不断的触发,如果想要确保也能获得全部的历史记录,就需要记住所有的参数。这是一种情况;实际可能还会有更多的流程依赖,当然对于流程控制有很多办法,也有很多库支持。比如promise和async。本文只是阐述了一个事件和方法的流程相关场景,也许对你有启发。
【JavaScript】让事件支持先发布后订阅的更多相关文章
- vue_组件间通信:自定义事件、消息发布与订阅、槽
自定义事件 只能用于 子组件 向 父组件 发送数据 可以取代函数类型的 props 在父组件: 给子组件@add-todo-event="addTodo" 在子组件: 相关方法中, ...
- javascript 自定义事件 发布-订阅 模式 Event
* javascript自定义事件 var myEvent = document.createEvent("Event"); myEvent.initEvent("myE ...
- javascript设计模式学习之八_发布订阅(观察者)模式
一.发布订阅模式定义 jQuery中的callbacks,defered,promise本质上就是发布订阅模式的实现.ES6的promise内部实现未开源,不了解具体机制 发布订阅模式又叫做观察者模式 ...
- 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码
最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
- Dapr实现.Net Grpc服务之间的发布和订阅,并采用WebApi类似的事件订阅方式
大家好,我是失业在家,正在找工作的博主Jerry,找工作之余,总结和整理以前的项目经验,动手写了个洋葱架构(整洁架构)示例解决方案 OnionArch.其目的是为了更好的实现基于DDD(领域驱动分析) ...
- C#事件支持发布者/订阅者模式(观察者模式)
C#事件支持发布者/订阅者模式,发布者将事件通知给订阅者,而订阅者在事件发生时调用已经注册好的事件处理函数. public delegate void delUpdate(); //委 ...
- Javascript事件模型系列(四)我所理解的javascript自定义事件
被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情,公司的个人的,搞的自己心烦意乱浮躁了一 ...
- 最详细的JavaScript和事件解读
与浏览器进行交互的时候浏览器就会触发各种事件.比如当我们打开某一个网页的时候,浏览器加载完成了这个网页,就会触发一个 load 事件:当我们点击页面中的某一个“地方”,浏览器就会在那个“地方”触发一个 ...
- [转] JavaScript 和事件
与浏览器进行交互的时候浏览器就会触发各种事件.比如当我们打开某一个网页的时候,浏览器加载完成了这个网页,就会触发一个 load 事件:当我们点击页面中的某一个“地方”,浏览器就会在那个“地方”触发一个 ...
随机推荐
- 混合高斯模型(GMM)推导及实现
作者:桂. 时间:2017-03-20 06:20:54 链接:http://www.cnblogs.com/xingshansi/p/6584555.html 声明:欢迎被转载,不过记得注明出处哦 ...
- Python3.6安装
1.安装依赖包#yum install -y openssl openssl-devel openssl-static#yum groupinstall -y "Development to ...
- python非转基因HTTP请求库--Requests: 让 HTTP 服务人类
快速上手 迫不及待了吗?本页内容为如何入门 Requests 提供了很好的指引.其假设你已经安装了 Requests.如果还没有,去安装一节看看吧. 首先,确认一下: Requests 已安装 Req ...
- PT20150801隆重开班
PT20150801隆重开班 伴随着秋天的的脚步,带着对梦想的憧憬,POPTEST1508期学员步入正式学习阶段:POPTEST的课程内容吸收了互联网公司先进技术的特点,同时坚持深入浅出的教育特点,完 ...
- Fragment深入解析
写在顶部表示这点很重要: 本文转载自博客:http://blog.csdn.net/lmj623565791/article/details/37970961 欢迎访问原文 自从Fragment ...
- linux从入门到精通学习-NFS
NFS网络文件系统 功能 nfs[network file system] 网络文件系统 是FreBSD系统支持的一种系统,允许在网络 上与其它人共享使用文件或文件夹 采用C/S模式 端口号 在vim ...
- 使用nodejs进行WEB开发
这里,准备从零开始用nodejs实现一个微博系统.功能包括路由控制.页面模板.数据库访问.用户注册.登录.用户会话等内容. 将会介绍Express框架.MVC设计模式.ejs模板引擎以及MongoDB ...
- UEditor使用------图片上传与springMVC集成 完整实例
UEditor是一个很强大的在线编辑软件 ,首先讲一下 基本的配置使用 ,如果已经会的同学可以直接跳过此节 ,今天篇文章重点说图片上传; 一 富文本的初始化使用: 1 首先将UEditor从官网下载 ...
- cocos2d-x - C++/Lua交互
使用tolua++将自定义的C++类嵌入,让lua脚本使用 一般过程: 自定义类 -> 使用tolua++工具编译到LuaCoco2d.cpp中 -> lua调用 步骤一:自定义一个C++ ...
- QT链接数据库
在介绍QT与数据的链接问题上,我在这里就不介绍关于QT环境与mysql.sqlite3环境的安装步骤了,以下的所有的操作都是建立在你已经安装了所有环境的基础上的.好的,那我们就具体来看一看QT环境中怎 ...