【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 事件:当我们点击页面中的某一个“地方”,浏览器就会在那个“地方”触发一个 ...
随机推荐
- Hibernate之关联映射(一对多和多对一映射,多对多映射)
~~~接着之前的Hibernate框架接着学习(上篇面试过后发现真的需要学习以下框架了,不然又被忽悠让去培训.)~~~ 1:Hibernate的关联映射,存在一对多和多对一映射,多对多映射: 1.1: ...
- Spring中一个类的注入和引用是不一样的
1.在Spring管理下的bean需要以下面这种方式引入(一种注入方式): private MgrService mgrService; public MgrService getMgrService ...
- Ant.SOA微服务框架开源
开源地址:https://github.com/yuzd/AntServiceStack 框架特色0.Service Management(服务治理) 1.CodeGen Contract Fir ...
- java与JSTL库
JSTL1. jstl的概述 * apache的东西,依赖EL * 使用jstl需要导入jstl1.2.jar * 四大库: > core:核心库,重点 > fmt:格式 ...
- Mycat安装与使用
1.下载: https://github.com/MyCATApache/Mycat-download 具体下载哪个版本以发布为准,推荐1.4,1.5. 2.安装: 安全前,在Linu ...
- as3中强制垃圾回收
private function doClearance():void { // trace("clear"); try{ new LocalConnection().connec ...
- 【转】HTML5 API --- 页面可见性改变(visibilitychange)事件
[摘要:[本文属本创,若有转载,请说明出处http://blog.csdn.net/yl02520/article/] visibilitychange事情是扫瞄器新增加的一个事情,当扫瞄器的某个标签 ...
- C#研究OpenXML之路(1-新建工作簿文件)
一.写在开头 一直想沉下心来研究研究OpenXML编程,可是由于公司编程项目一笔接一笔,很难静下来,所以一直是采用的COM操作Excel.现在终于得闲,特将心得历程记录下来. 今天的第一个实例代码是来 ...
- 性能调优之剖析OutOfMemoryError
性能调优之剖析OutOfMemoryError poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询q ...
- 老李分享:Web Services 组件 1
老李分享:Web Services 组件 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:9 ...