fastevent 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme_cn.md CHANGED
@@ -4,9 +4,9 @@ FastEvent 是一个功能强大的`TypeScript`事件管理库,提供了灵活
4
4
 
5
5
  对比`EventEmitter2`,`FastEvent`具有以下优势:
6
6
 
7
- - 在含通配符发布与订阅时,`FastEvent`的性能比`EventEmitter2`高 `1+`倍左右。
8
- - `FastEvent`包大小为 `6.3xkb`,而`EventEmitter2`为 `43.4kb`。
9
- - `FastEvent`拥有更丰富的功能。
7
+ - `FastEvent`的性能比`EventEmitter2`高 `1~2`倍左右。
8
+ - `FastEvent`包大小为 `6.xkb`,而`EventEmitter2`为 `43.4kb`。
9
+ - `FastEvent`拥有更丰富的功能。
10
10
 
11
11
  # 安装
12
12
 
@@ -33,47 +33,67 @@ import { FastEvent } from 'fastevent';
33
33
  const events = new FastEvent();
34
34
 
35
35
  // 订阅事件
36
- events.on('user/login', (user) => {
37
- console.log('用户登录:', user);
36
+ events.on('user/login', (message) => {
37
+ console.log('用户登录:', message.payload);
38
+ console.log('事件类型:', message.type);
39
+ console.log('元数据:', message.meta);
38
40
  });
39
41
 
40
- // 发布事件
42
+ // 发布事件 - 方式1:参数形式
41
43
  events.emit('user/login', { id: 1, name: 'Alice' });
44
+
45
+ // 发布事件 - 方式2:消息对象形式
42
46
  events.emit({
43
- type:'user/login',
44
- payload:{ id: 1, name: 'Alice' }
45
- });
47
+ type: 'user/login',
48
+ payload: { id: 1, name: 'Alice' },
49
+ meta: { timestamp: Date.now() },
50
+ });
46
51
  ```
47
52
 
48
53
  # 指南
49
54
 
55
+ ## 事件消息格式
56
+
57
+ FastEvent 使用标准化的消息格式处理所有事件:
58
+
59
+ ```typescript
60
+ type FastEventMessage<T = string, P = any, M = unknown> = {
61
+ type: T; // 事件类型
62
+ payload: P; // 事件数据
63
+ meta: M; // 事件元数据
64
+ };
65
+ ```
66
+
67
+ 事件监听器始终接收这个消息对象,提供了一致的方式来访问事件数据和元数据。
68
+
50
69
  ## 事件通配符
51
70
 
52
71
  FastEvent 支持两种通配符:
53
- - `*`: 匹配单层路径
54
- - `**`: 匹配多层路径
72
+
73
+ - `*`: 匹配单层路径
74
+ - `**`: 匹配多层路径
55
75
 
56
76
  ```typescript
57
77
  const events = new FastEvent();
58
78
 
59
79
  // 匹配 user/*/login
60
- events.on('user/*/login', (data) => {
61
- console.log('任何用户类型的登录:', data);
80
+ events.on('user/*/login', (message) => {
81
+ console.log('任何用户类型的登录:', message.payload);
62
82
  });
63
83
 
64
84
  // 匹配 user 下的所有事件
65
- events.on('user/**', (data) => {
66
- console.log('所有用户相关事件:', data);
85
+ events.on('user/**', (message) => {
86
+ console.log('所有用户相关事件:', message.payload);
67
87
  });
68
88
 
69
89
  // 触发事件
70
- events.emit('user/admin/login', { id: 1 }); // 两个处理器都会被调用
71
- events.emit('user/admin/profile/update', { name: 'New' }); // 只有 ** 处理器会被调用
90
+ events.emit('user/admin/login', { id: 1 }); // 两个处理器都会被调用
91
+ events.emit('user/admin/profile/update', { name: 'New' }); // 只有 ** 处理器会被调用
72
92
  ```
73
93
 
74
94
  ## 事件作用域
75
95
 
76
- 作用域允许你在特定的命名空间下处理事件:
96
+ 作用域允许你在特定的命名空间下处理事件。注意,作用域与父事件发射器共享相同的监听器表:
77
97
 
78
98
  ```typescript
79
99
  const events = new FastEvent();
@@ -81,13 +101,59 @@ const events = new FastEvent();
81
101
  // 创建用户相关的作用域
82
102
  const userScope = events.scope('user');
83
103
 
84
- // 在作用域中订阅事件
85
- userScope.on('login', (data) => {
86
- console.log('用户登录:', data);
87
- });
104
+ // 以下两种方式等效:
105
+ userScope.on('login', handler);
106
+ events.on('user/login', handler);
107
+
108
+ // 以下两种方式也等效:
109
+ userScope.emit('login', data);
110
+ events.emit('user/login', data);
111
+
112
+ // 清除作用域中的所有监听器
113
+ userScope.offAll(); // 等效于 events.offAll('user')
114
+ ```
115
+
116
+ ## 监听器选项
117
+
118
+ 订阅事件时可以指定额外的选项:
119
+
120
+ ```typescript
121
+ interface FastEventListenOptions {
122
+ // 监听器被调用的次数(0表示无限次,1表示一次)
123
+ count?: number;
124
+ // 将监听器添加到监听器数组的开头
125
+ prepend?: boolean;
126
+ }
127
+
128
+ // 示例:监听前3次事件
129
+ events.on('data', handler, { count: 3 });
130
+
131
+ // 示例:确保处理器在其他监听器之前被调用
132
+ events.on('important', handler, { prepend: true });
133
+ ```
134
+
135
+ ## 移除监听器
136
+
137
+ FastEvent 提供多种移除监听器的方式:
138
+
139
+ ```typescript
140
+ // 移除特定监听器
141
+ events.off(listener);
142
+
143
+ // 移除某个事件的所有监听器
144
+ events.off('user/login');
145
+
146
+ // 移除某个事件的特定监听器
147
+ events.off('user/login', listener);
148
+
149
+ // 使用通配符模式移除监听器
150
+ events.off('user/*');
151
+
152
+ // 移除所有监听器
153
+ events.offAll();
88
154
 
89
- // 等同于 events.emit('user/login', data)
90
- userScope.emit('login', { id: 1 });
155
+ // 移除某个前缀下的所有监听器
156
+ events.offAll('user');
91
157
  ```
92
158
 
93
159
  ## 一次性事件
@@ -98,11 +164,11 @@ userScope.emit('login', { id: 1 });
98
164
  const events = new FastEvent();
99
165
 
100
166
  events.once('startup', () => {
101
- console.log('应用启动');
167
+ console.log('应用启动');
102
168
  });
103
169
 
104
- events.emit('startup'); // 输出: 应用启动
105
- events.emit('startup'); // 无输出,监听器已被移除
170
+ // 等效于:
171
+ events.on('startup', handler, { count: 1 });
106
172
  ```
107
173
 
108
174
  ## 异步事件
@@ -113,15 +179,42 @@ events.emit('startup'); // 无输出,监听器已被移除
113
179
  const events = new FastEvent();
114
180
 
115
181
  events.on('data/fetch', async () => {
116
- const response = await fetch('https://api.example.com/data');
117
- return await response.json();
182
+ const response = await fetch('https://api.example.com/data');
183
+ return await response.json();
118
184
  });
119
185
 
120
- // 异步发布事件
186
+ // 异步发布事件返回所有结果/错误的数组
121
187
  const results = await events.emitAsync('data/fetch');
122
188
  console.log('所有处理器的结果:', results);
123
189
  ```
124
190
 
191
+ ## 监听器返回值
192
+
193
+ `emit` 和 `emitAsync` 方法都会返回所有事件监听器的执行结果:
194
+
195
+ ```typescript
196
+ const events = new FastEvent();
197
+
198
+ // 同步监听器的返回值
199
+ events.on('calculate', () => 1);
200
+ events.on('calculate', () => 2);
201
+ events.on('calculate', () => 3);
202
+
203
+ // 获取返回值数组
204
+ const results = events.emit('calculate');
205
+ console.log('结果:', results); // [1, 2, 3]
206
+
207
+ // 异步监听器
208
+ events.on('process', async () => '结果 1');
209
+ events.on('process', async () => '结果 2');
210
+
211
+ // 获取异步结果/错误数组
212
+ const asyncResults = await events.emitAsync('process');
213
+ console.log('异步结果:', asyncResults); // ['结果 1', '结果 2']
214
+ ```
215
+
216
+ 对于异步事件,`emitAsync` 会等待所有监听器完成执行,并返回一个数组,包含所有监听器的解析值,如果监听器执行失败则包含错误对象。
217
+
125
218
  ## 事件等待
126
219
 
127
220
  使用 `waitFor` 等待特定事件发生:
@@ -130,13 +223,13 @@ console.log('所有处理器的结果:', results);
130
223
  const events = new FastEvent();
131
224
 
132
225
  async function waitForLogin() {
133
- try {
134
- // 等待登录事件,超时时间 5 秒
135
- const userData = await events.waitFor('user/login', 5000);
136
- console.log('用户已登录:', userData);
137
- } catch (error) {
138
- console.log('登录等待超时');
139
- }
226
+ try {
227
+ // 等待登录事件,超时时间 5 秒
228
+ const userData = await events.waitFor('user/login', 5000);
229
+ console.log('用户已登录:', userData);
230
+ } catch (error) {
231
+ console.log('登录等待超时');
232
+ }
140
233
  }
141
234
 
142
235
  waitForLogin();
@@ -155,8 +248,8 @@ const events = new FastEvent();
155
248
  events.emit('config/update', { theme: 'dark' }, true);
156
249
 
157
250
  // 之后的订阅者会立即收到保留的数据
158
- events.on('config/update', (config) => {
159
- console.log('配置:', config); // 立即输出: 配置: { theme: 'dark' }
251
+ events.on('config/update', (message) => {
252
+ console.log('配置:', message.payload); // 立即输出: 配置: { theme: 'dark' }
160
253
  });
161
254
  ```
162
255
 
@@ -168,7 +261,7 @@ events.on('config/update', (config) => {
168
261
 
169
262
  ```typescript
170
263
  const events = new FastEvent({
171
- delimiter: '.'
264
+ delimiter: '.',
172
265
  });
173
266
  ```
174
267
 
@@ -179,12 +272,12 @@ const events = new FastEvent({
179
272
  ```typescript
180
273
  const events = new FastEvent();
181
274
 
182
- events.onAny((data, meta) => {
183
- console.log(`事件 ${meta.type} 被触发:`, data);
275
+ events.onAny((message) => {
276
+ console.log(`事件 ${message.type} 被触发:`, message.payload);
184
277
  });
185
278
 
186
- events.emit('user/login', { id: 1 }); // 输出: 事件 user/login 被触发: { id: 1 }
187
- events.emit('system/error', 'Connection failed'); // 输出: 事件 system/error 被触发: Connection failed
279
+ // 也可以使用 prepend 选项
280
+ events.onAny(handler, { prepend: true });
188
281
  ```
189
282
 
190
283
  ## 元数据(Meta)
@@ -197,15 +290,15 @@ events.emit('system/error', 'Connection failed'); // 输出: 事件 system/erro
197
290
 
198
291
  ```typescript
199
292
  const events = new FastEvent({
200
- meta: {
201
- version: '1.0',
202
- environment: 'production'
203
- }
293
+ meta: {
294
+ version: '1.0',
295
+ environment: 'production',
296
+ },
204
297
  });
205
298
 
206
- events.on('user/login', (data, meta) => {
207
- console.log('事件数据:', data);
208
- console.log('元数据:', meta); // 包含 type、version 和 environment
299
+ events.on('user/login', (message) => {
300
+ console.log('事件数据:', message.payload);
301
+ console.log('元数据:', message.meta); // 包含 type、version 和 environment
209
302
  });
210
303
  ```
211
304
 
@@ -215,20 +308,21 @@ events.on('user/login', (data, meta) => {
215
308
 
216
309
  ```typescript
217
310
  const events = new FastEvent({
218
- meta: { app: 'MyApp' }
311
+ meta: { app: 'MyApp' },
219
312
  });
220
313
 
221
314
  // 在发布事件时添加特定的元数据
222
- events.emit('order/create',
223
- { orderId: '123' }, // 事件数据
224
- false, // 不保留
225
- { timestamp: Date.now() } // 事件特定的元数据
315
+ events.emit(
316
+ 'order/create',
317
+ { orderId: '123' }, // 事件数据
318
+ false, // 不保留
319
+ { timestamp: Date.now() }, // 事件特定的元数据
226
320
  );
227
321
 
228
322
  // 监听器接收合并后的元数据
229
- events.on('order/create', (data, meta) => {
230
- console.log('订单:', data); // { orderId: '123' }
231
- console.log('元数据:', meta); // { type: 'order/create', app: 'MyApp', timestamp: ... }
323
+ events.on('order/create', (message) => {
324
+ console.log('订单:', message.payload); // { orderId: '123' }
325
+ console.log('元数据:', message.meta); // { type: 'order/create', app: 'MyApp', timestamp: ... }
232
326
  });
233
327
  ```
234
328
 
@@ -238,20 +332,47 @@ FastEvent 提供了错误处理机制:
238
332
 
239
333
  ```typescript
240
334
  const events = new FastEvent({
241
- ignoreErrors: true, // 默认为 true,不会抛出错误
242
- onListenerError: (type, error) => {
243
- console.error(`处理事件 ${type} 时发生错误:`, error);
244
- }
335
+ ignoreErrors: true, // 默认为 true,不会抛出错误
336
+ onListenerError: (type, error) => {
337
+ console.error(`处理事件 ${type} 时发生错误:`, error);
338
+ },
245
339
  });
246
340
 
247
341
  events.on('process', () => {
248
- throw new Error('处理失败');
342
+ throw new Error('处理失败');
249
343
  });
250
344
 
251
345
  // 不会抛出错误,而是触发 onListenerError
252
346
  events.emit('process');
253
347
  ```
254
348
 
349
+ ## TypeScript 类型支持
350
+
351
+ FastEvent 使用 TypeScript 编写,提供完整的类型支持:
352
+
353
+ ```typescript
354
+ // 定义事件类型
355
+ interface MyEvents {
356
+ 'user/login': { id: number; name: string };
357
+ 'user/logout': { id: number };
358
+ }
359
+
360
+ // 创建带类型的事件发射器
361
+ const events = new FastEvent<MyEvents>();
362
+
363
+ // 事件名称和数据类型检查
364
+ events.on('user/login', (message) => {
365
+ // message.payload 的类型为 { id: number; name: string }
366
+ const { id, name } = message.payload;
367
+ });
368
+
369
+ // 错误:错误的事件名称
370
+ events.emit('wrong/event', {});
371
+
372
+ // 错误:错误的数据类型
373
+ events.emit('user/login', { wrong: 'type' });
374
+ ```
375
+
255
376
  ## 自定义选项
256
377
 
257
378
  FastEvent 构造函数支持多个选项:
@@ -259,18 +380,18 @@ FastEvent 构造函数支持多个选项:
259
380
  ```typescript
260
381
  const events = new FastEvent({
261
382
  // 事件路径分隔符,默认为 '/'
262
- delimiter: '.',
383
+ delimiter: '.',
263
384
  // 事件处理器的上下文
264
- context: null,
385
+ context: null,
265
386
  // 元数据,会传递给所有事件处理器
266
- meta: { ... },
267
-
387
+ meta: { ... },
388
+
268
389
  // 错误处理
269
390
  ignoreErrors: true,
270
391
  onListenerError: (type, error) => {
271
392
  console.error(`事件错误:`, type, error);
272
393
  },
273
-
394
+
274
395
  // 监听器添加/移除的回调
275
396
  onAddListener: (path, listener) => {
276
397
  console.log('添加监听器:', path);
@@ -283,4 +404,4 @@ const events = new FastEvent({
283
404
 
284
405
  # 性能
285
406
 
286
- ![](./bench.png)
407
+ ![](./bench.png)
@@ -1,107 +1,106 @@
1
1
  import { describe, test, expect } from "vitest"
2
- import { FastEvent } from "../event"
2
+ import { FastEvent } from "../event"
3
3
 
4
- describe("简单发布与订阅",async ()=>{
5
- test("简单发布订阅事件",()=>{
6
- const emitter = new FastEvent()
7
- emitter.on("x",(payload,{type})=>{
4
+ describe("简单发布与订阅", async () => {
5
+ test("简单发布订阅事件", () => {
6
+ const emitter = new FastEvent()
7
+ emitter.on("x", ({ type, payload }) => {
8
8
  expect(type).toBe("x")
9
- expect(payload).toBe(1)
9
+ expect(payload).toBe(1)
10
10
  })
11
- emitter.emit("x",1)
11
+ emitter.emit("x", 1)
12
12
  })
13
- test("简单发布订阅事件后取消",()=>{
14
- const emitter = new FastEvent()
15
- const events:string[]=[]
16
- const subscriber = emitter.on("x",(payload,{type})=>{
13
+ test("简单发布订阅事件后取消", () => {
14
+ const emitter = new FastEvent()
15
+ const events: string[] = []
16
+ const subscriber = emitter.on("x", ({ type, payload }) => {
17
17
  expect(type).toBe("x")
18
- expect(payload).toBe(1)
19
- events.push(type)
18
+ expect(payload).toBe(1)
19
+ events.push(type)
20
20
  })
21
- emitter.emit("x",1)
21
+ emitter.emit("x", 1)
22
22
  expect(events).toEqual(["x"])
23
23
  subscriber.off()
24
- emitter.emit("x",1)
25
- emitter.emit("x",1)
26
- emitter.emit("x",1)
24
+ emitter.emit("x", 1)
25
+ emitter.emit("x", 1)
26
+ emitter.emit("x", 1)
27
27
  expect(events).toEqual(["x"])
28
- })
29
- test("发布订阅层级事件",()=>{
30
- const emitter = new FastEvent()
31
- const events:string[]=[]
32
- emitter.on("a.b.c",(payload,{type})=>{
28
+ })
29
+ test("发布订阅层级事件", () => {
30
+ const emitter = new FastEvent()
31
+ const events: string[] = []
32
+ emitter.on("a.b.c", ({ type, payload }) => {
33
33
  expect(type).toBe("a.b.c")
34
- expect(payload).toBe(1)
35
- events.push(type)
34
+ expect(payload).toBe(1)
35
+ events.push(type)
36
36
  })
37
- emitter.emit("a",1)
38
- emitter.emit("a.b",1)
39
- emitter.emit("a.b.c",1)
37
+ emitter.emit("a", 1)
38
+ emitter.emit("a.b", 1)
39
+ emitter.emit("a.b.c", 1)
40
40
  expect(events).toEqual(["a.b.c"])
41
41
  })
42
- test("返回事件执行结果",()=>{
43
- const emitter = new FastEvent()
44
- for(let i=1;i<=10;i++){
45
- emitter.on("x",()=>{
42
+ test("返回事件执行结果", () => {
43
+ const emitter = new FastEvent()
44
+ for (let i = 1; i <= 10; i++) {
45
+ emitter.on("x", () => {
46
46
  return i
47
47
  })
48
48
  }
49
- const results = emitter.emit("x",1)
50
- expect(results).toEqual([1,2,3,4,5,6,7,8,9,10])
49
+ const results = emitter.emit("x", 1)
50
+ expect(results).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
51
51
  })
52
- test("侦听器执行出错返回事件执行结果",async ()=>{
53
- const emitter = new FastEvent()
54
- for(let i=1;i<=10;i++){
55
- emitter.on("x",()=>{
56
- if(i % 2 ==0) throw new Error("custom")
52
+ test("侦听器执行出错返回事件执行结果", async () => {
53
+ const emitter = new FastEvent()
54
+ for (let i = 1; i <= 10; i++) {
55
+ emitter.on("x", () => {
56
+ if (i % 2 == 0) throw new Error("custom")
57
57
  return i
58
58
  })
59
59
  }
60
- const results = emitter.emit("x",1)
61
- for(let i=1;i<=10;i++){
62
- if(i % 2 ==0) expect(results[i-1]).toBeInstanceOf(Error)
63
- else expect(results[i-1]).toBe(i)
60
+ const results = emitter.emit("x", 1)
61
+ for (let i = 1; i <= 10; i++) {
62
+ if (i % 2 == 0) expect(results[i - 1]).toBeInstanceOf(Error)
63
+ else expect(results[i - 1]).toBe(i)
64
64
  }
65
65
  })
66
- test("侦听器执行出错时emit出错",async ()=>{
67
- const emitter = new FastEvent({ignoreErrors:false})
66
+ test("侦听器执行出错时emit出错", async () => {
67
+ const emitter = new FastEvent({ ignoreErrors: false })
68
68
  const err = new Error("custom")
69
- for(let i=1;i<=10;i++){
70
- emitter.on("x",()=>{
71
- if(i % 2 ==0) throw err
69
+ for (let i = 1; i <= 10; i++) {
70
+ emitter.on("x", () => {
71
+ if (i % 2 == 0) throw err
72
72
  return i
73
73
  })
74
74
  }
75
- expect(()=>emitter.emit("x",1)).toThrow(err);
75
+ expect(() => emitter.emit("x", 1)).toThrow(err);
76
76
  // @ts-ignore, 当执行侦听器出错时会在错误对象上挂载一个_listener属性代表当前执行的侦听器路径
77
- expect(err._trigger).toBe("x")
78
-
77
+ expect(err._emitter).toBe("x")
78
+
79
79
  })
80
- test("添加侦听器时指定顺序",async ()=>{
81
- const emitter = new FastEvent()
82
- const types:number[]=[]
83
- emitter.on("x",()=>{
80
+ test("添加侦听器时指定顺序", async () => {
81
+ const emitter = new FastEvent()
82
+ const types: number[] = []
83
+ emitter.on("x", () => {
84
84
  types.push(1)
85
85
  })
86
-
87
- emitter.on("x",()=>{
86
+
87
+ emitter.on("x", () => {
88
88
  types.push(2)
89
- },{prepend:true})
89
+ }, { prepend: true })
90
90
  emitter.emit("x")
91
- expect(types).toEqual([2,1])
92
- })
93
- test("简单发布订阅message事件",()=>{
94
- const emitter = new FastEvent()
95
- emitter.on("x",(payload,meta)=>{
96
- expect(meta.type).toBe("x")
91
+ expect(types).toEqual([2, 1])
92
+ })
93
+ test("简单发布订阅message事件", () => {
94
+ const emitter = new FastEvent()
95
+ emitter.on("x", ({ type, payload, meta }) => {
96
+ expect(type).toBe("x")
97
97
  expect(meta.a).toBe(1)
98
98
  expect(payload).toBe(1)
99
99
  })
100
100
  emitter.emit({
101
- type:"x",
102
- payload:1,
103
- meta:{a:1}
101
+ type: "x",
102
+ payload: 1,
103
+ meta: { a: 1 }
104
104
  })
105
- })
106
- })
107
-
105
+ })
106
+ })