如何打造一个带类型的事件系统

底层看你自己选择了,萝卜青菜各有所爱,我是基于 proto 开发的

实现只是顺序字节写入,使用还是很方便的,我写好注释就非常容易理解了。

好好好,cv一下

不明白你这两种方式有啥区别,我是为了更贴合真实RPC调用才这样实现的,比如远程服务器有一个RPC服务:


前端TS调用可以这样:

    Global.remotingInvoke("DemoService:sum", [1, 1000]).then(res => {
        console.log("远程计算两数之间所有数字之和:" + res);
    }).catch(err => {
        console.log(err);
    });

还可以如下这样:
服务端:


客户端调用:

我是从 tsrpc 这个项目中第一次看到这种用法,这种无论怎样,都是要有一个数据和消息的关连关系来辅助类型推断。
要么在消息数据体 data 中,要么是对应关系映射表。

其中映射表的方式除了集中式(事件一般是集中式)。还可以用 global declare {
interface XX {
[event_name]: event_data_type


进行分布式定义。而这种机制可以泛化到【类型到类】【类型到函数】【类型到类型】,这种机制的复用让理解成本更低。

8赞

TS的类型比C#要强大,很多C#办不到或很难办到的,用TS就比较好实现。

按我的理解事件系统是为了解决“你中无我,我中无你,但是我们俩还想通信”,或者是为了达到“你中无我,我中无你”的状态而引入事件系统以求解耦。还有一种情况比较简单“你中有我,但是我中不能有你,因为可能循环引用”,虽然可以用接口去解决,但是也可以用事件系统达到目的。
题主的事件系统能搞这么复杂,也是让人头皮发麻,没有看下去的欲望,我一度以为我理解的事件系统和题主理解的不是一回事,我都懒得造轮子,感觉造出来也没啥意义,直接用的EventEmitter3,只是简单封装了下,封装的目的是为了方便使用仅此而已。
源码:


例子:

代码提示:
image

我觉得这就够了,而且type申明的类型构建后也擦除了

1赞

这个类型 最后其实就是直接调用了那个函数本身 不算是发消息就是找到那个对象的地址直接发消息差不多的样子,事件系统一般就是向世界抛出一个事件谁监听了这个时间 谁就可以获取到这个事件的数据

直接用game.emit 感觉一样的呀 :grinning:

就是为了解耦才用事件,结果还给事件类型耦合起来…

楼主是为了解决数据类型约束,不过方案过于复杂

耦合的主体有区别,你说的是调用主体解耦。楼主说的是事件派发的数据类型约束

你这个 IEvent 类型方案其实和 MK 的类似,我以前尝试过,结论是:不好用。会有几个问题点
1、集中式的声明。有些逻辑其实是分包的,这个 IEvent 没有支持分布式定义。(当然 declare global 可解决这个问题)
2、所有事件都要声明(这个比较蛋疼,越用越难受)
3、事件处理函数有时候是多个函数。有的函数只心事件,不关心参数,通常是类似 refreshUI() 的刷新函数,而注册时就会报红,导致必须加 as any 这类的特殊处理。难受。

我的方案就是,通过约定做隐式数据约束。

emit<DATA = any>(name: string | number, data: DATA = null)

on<DATA = any>(name: string | number, cb: (data?: DATA) => any, ctx: any): EventBox;

于是,在开发的时候:
1、派发的地方有数据,前面的类型一定要补上,方便知道是什么数据类型;
2、监听的地方,一定根据派发的数据约束写上数据约束(不写表示只关心事件本身);
3、在新增消息处理函数的时候,只要查一下别的地方怎么用,然后做同样的约束。
4、派发数据更改时(重构)的时候。也是查下消息的引用。统一修改各个监听函数的处理逻辑的。

这套逻辑流程用起来最舒服。

1赞

ikun 2.5 year :ok_hand: :rofl:

最佩服一个事件系统都可以有自己一套理论的人了 :+1:

两个emitter 更难用

我只能说明你的不好用是针对你自己的,原因如下

  1. 分布式定义事件类型是最差的方案,因为不能一眼看到有什么事件,只有自己知道或者利用编辑器查看引用,这本身就是浪费时间和协作开发的拖累

  2. 事件类型只需要定义一次,和 Enum 方案相比只是多了几个参数但是保证了类型安全

  3. 事件必须关注参数,除非你不用事件参数,或者不在乎事件参数类型和数量是否正确
    你的方案就是直接忽略事件参数校验,我可以随便传递任何类型的事件参数但是不会在编辑器报错,只有运行时报错

1赞

最最佩服的是拿这套理论去成功说服团队使用 :rofl: