使用typescript 写一个简单的事件监听/发布订阅模式的类

我们需要弄清楚,观察者模式和发布订阅模式是不一样的,一张图理解:

两者区别:

  1. 观察者 模式只有观察者和被观察者两者,是松耦合

  2. 发布订阅模式除了发布者和订阅者外,还有一个调度中心,是解耦的,两者没有直接关系

  3. 观察者主要是同步方式实现,二发布订阅模式多数是异步实现,比如消息队列

用typescript 简单实现一个发布订阅模式的类

 1 class byEvent {
 2     Events: { [key: string]: Array<Function> } //约束示例:{"eventName":[function(){},function(){},.....],......}
 3     constructor() {
 4         this.Events = {}
 5     }
 6     /**
 7      * 发布/ 触发
 8      * @param eventName 
 9      * @param args 
10      */
11     emit(eventName: string, ...args: any) {
12         let callbackList = this.Events[eventName] || [];
13         callbackList.forEach(fn => fn.apply(this, args))
14         return this;
15         // 如果用js写,遍历的时候要做一下判断是否是函数,ts 用类型约束,在调用或者编译阶段会检测是否合法
16         // callbackList.map(fn=>{
17         //     if(typeof fn==="function") fn.apply(this,args)
18         // })
19     }
20     /**
21      * 订阅/监听
22      * @param eventName 
23      * @param callback 
24      */
25     on(eventName: string, callback?: Function) {
26         // if(!eventName||typeof eventName !=="string") return  ;// 因为用了ts 写,所以这句不用写了,如果是js写,建议加这判断
27         let callbackList = this.Events[eventName] || [];
28         callback && callbackList.push(callback)
29         this.Events[eventName] = callbackList
30         return this;
31 
32     }
33     /**
34      * 只订阅一次/监听一次:
35      * 思路:
36      * 1. 重新包装一个回调函数(有名的),进行注册订阅/监听,
37      * 2. 包装函数里面直接调用 once方法的第二个参数回调函数,然后调用off方法 卸载该包装函数
38      * @param eventName 
39      * @param callback 
40      */
41     once(eventName: string, callback?: Function) {
42         // if(!eventName||typeof eventName !=="string") return ;
43         let decor = (...args: any[]) => {
44             callback && callback.apply(this, args)
45             this.off(eventName, decor)
46         }
47         this.on(eventName, decor)
48         return this;
49 
50     }
51     /**
52      * 卸载/取消 某一个回调监听(不是取消eventName的所有回调监听),主要配合once一起,实例单独调用,无意义
53      * @param eventName 
54      * @param callback 
55      */
56     off(eventName: string, callback: Function) {
57         let callbackList = this.Events[eventName] || [];
58         let resCallbacks = callbackList.filter(fn => fn !== callback)
59         this.Events[eventName] = resCallbacks
60         return this;
61 
62     }
63     /**
64      * 卸载/取消 指定eventName 的所有订阅/监听
65      * @param eventName 
66      * @param callback 
67      */
68     remove(eventName: string, callback?: Function) {
69         this.Events[eventName] = [];
70         callback && callback()
71         return this;
72 
73     }
74 
75 }
76 
77 // 使用示例
78 let o = new byEvent()
79 setInterval(() => {
80     o.emit("name", 123)
81     o.emit("name", 10, 20)
82     o.emit("post", { name: 1212 }, "post")
83 
84 }, 1000);
85 setTimeout(() => {
86     o.remove("name", function () {
87         console.log("remove")
88     })
89 }, 3000)
90 o.once("name", function (...res: any[]) {
91     console.log("once-name1", res)
92 })
93 o.on("name", function (...res: any[]) {
94     console.log("on-name2", res)
95 })
96 o.on("post", function (...res: any[]) {
97     console.log("on-post", res)
98 }

 

posted @ 2020-08-31 17:39  天高任鸟飞吧  阅读(3605)  评论(0编辑  收藏  举报