@taicode/common-base 1.7.3 → 1.7.4

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.
@@ -183,24 +183,98 @@ describe('FlowQueue', () => {
183
183
  });
184
184
  });
185
185
  describe('并发处理', () => {
186
- it('应该防止并发处理', async () => {
186
+ it('应该支持配置的并发数量', async () => {
187
187
  const inputs = [
188
188
  { id: 1, data: 'test1' },
189
- { id: 2, data: 'test2' }
189
+ { id: 2, data: 'test2' },
190
+ { id: 3, data: 'test3' },
191
+ { id: 4, data: 'test4' }
190
192
  ];
191
- // 模拟较慢的处理器
193
+ let processingCount = 0;
194
+ let maxConcurrentProcessing = 0;
195
+ // 模拟较慢的处理器,用来测试并发
192
196
  mockProcessor = vi.fn().mockImplementation(async (input) => {
197
+ processingCount++;
198
+ maxConcurrentProcessing = Math.max(maxConcurrentProcessing, processingCount);
199
+ await new Promise(resolve => setTimeout(resolve, 50));
200
+ processingCount--;
201
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
202
+ });
203
+ // 创建支持 3 个并发的队列
204
+ flowQueue = new FlowQueue({
205
+ retry: { maxRetries: 3 },
206
+ concurrency: 3
207
+ }, mockProcessor);
208
+ // 添加所有输入
209
+ flowQueue.input(...inputs);
210
+ flowQueue.closeInput();
211
+ await flowQueue.awaitCompletion();
212
+ // 验证结果
213
+ expect(mockProcessor).toHaveBeenCalledTimes(4);
214
+ expect(flowQueue.successOutputs.size).toBe(4);
215
+ expect(maxConcurrentProcessing).toBe(3); // 应该达到配置的并发数
216
+ });
217
+ it('默认应该使用并发数 1(顺序处理)', async () => {
218
+ const inputs = [
219
+ { id: 1, data: 'test1' },
220
+ { id: 2, data: 'test2' },
221
+ { id: 3, data: 'test3' }
222
+ ];
223
+ let processingCount = 0;
224
+ let maxConcurrentProcessing = 0;
225
+ const processingOrder = [];
226
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
227
+ processingCount++;
228
+ maxConcurrentProcessing = Math.max(maxConcurrentProcessing, processingCount);
229
+ processingOrder.push(input.id);
193
230
  await new Promise(resolve => setTimeout(resolve, 30));
231
+ processingCount--;
194
232
  return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
195
233
  });
234
+ // 使用默认配置(并发数应该为 1)
196
235
  flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
197
- // 快速添加两个输入
198
- flowQueue.input(inputs[0]);
199
- flowQueue.input(inputs[1]);
200
- await new Promise(resolve => setTimeout(resolve, 100));
201
- // 应该按顺序处理
202
- expect(mockProcessor).toHaveBeenCalledTimes(2);
203
- expect(flowQueue['processedInputs'].length).toBe(2);
236
+ flowQueue.input(...inputs);
237
+ flowQueue.closeInput();
238
+ await flowQueue.awaitCompletion();
239
+ // 验证顺序处理
240
+ expect(maxConcurrentProcessing).toBe(1);
241
+ expect(processingOrder).toEqual([1, 2, 3]); // 应该按顺序处理
242
+ });
243
+ it('应该在达到并发限制时等待', async () => {
244
+ const inputs = [
245
+ { id: 1, data: 'test1' },
246
+ { id: 2, data: 'test2' },
247
+ { id: 3, data: 'test3' },
248
+ { id: 4, data: 'test4' },
249
+ { id: 5, data: 'test5' }
250
+ ];
251
+ let activeProcessing = 0;
252
+ let maxActiveProcessing = 0;
253
+ const processStartTimes = [];
254
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
255
+ processStartTimes.push(Date.now());
256
+ activeProcessing++;
257
+ maxActiveProcessing = Math.max(maxActiveProcessing, activeProcessing);
258
+ await new Promise(resolve => setTimeout(resolve, 80));
259
+ activeProcessing--;
260
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
261
+ });
262
+ // 创建并发数为 2 的队列
263
+ flowQueue = new FlowQueue({
264
+ retry: { maxRetries: 3 },
265
+ concurrency: 2
266
+ }, mockProcessor);
267
+ const startTime = Date.now();
268
+ flowQueue.input(...inputs);
269
+ flowQueue.closeInput();
270
+ await flowQueue.awaitCompletion();
271
+ // 验证并发限制生效
272
+ expect(maxActiveProcessing).toBe(2);
273
+ expect(flowQueue.successOutputs.size).toBe(5);
274
+ // 验证第3个任务等待了前面任务完成
275
+ // 由于并发数为2,第3个任务应该在第一批任务完成后才开始
276
+ const totalTime = Date.now() - startTime;
277
+ expect(totalTime).toBeGreaterThan(150); // 至少需要两轮处理
204
278
  });
205
279
  });
206
280
  describe('边界情况', () => {
@@ -676,7 +750,7 @@ describe('FlowQueue', () => {
676
750
  expect(flowQueue['processedInputs'].length).toBe(0);
677
751
  expect(flowQueue.successOutputs.size).toBe(0);
678
752
  expect(flowQueue['retryCount'].size).toBe(0);
679
- expect(flowQueue['isProcessing']).toBe(false);
753
+ expect(flowQueue['processingCount']).toBe(0);
680
754
  expect(flowQueue['isInputClosed']).toBe(false);
681
755
  expect(flowQueue['completionPromise']).toBe(null);
682
756
  expect(flowQueue['completionResolve']).toBe(null);
@@ -1030,4 +1104,101 @@ describe('FlowQueue', () => {
1030
1104
  });
1031
1105
  });
1032
1106
  });
1107
+ describe('链式调用', () => {
1108
+ it('应该支持 input 方法的链式调用', async () => {
1109
+ const inputs = [
1110
+ { id: 1, data: 'test1' },
1111
+ { id: 2, data: 'test2' },
1112
+ { id: 3, data: 'test3' }
1113
+ ];
1114
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1115
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1116
+ });
1117
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1118
+ // 测试链式调用并验证返回值
1119
+ const returnValue = flowQueue
1120
+ .input(inputs[0])
1121
+ .input(inputs[1], inputs[2]);
1122
+ expect(returnValue).toBe(flowQueue); // 验证返回的是同一个实例
1123
+ flowQueue.closeInput();
1124
+ await flowQueue.awaitCompletion();
1125
+ expect(flowQueue.successOutputs.size).toBe(3);
1126
+ });
1127
+ it('应该支持 closeInput 方法的链式调用', async () => {
1128
+ const testInput = { id: 1, data: 'test' };
1129
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1130
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1131
+ });
1132
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1133
+ // 测试链式调用
1134
+ const returnValue = flowQueue
1135
+ .input(testInput)
1136
+ .closeInput();
1137
+ expect(returnValue).toBe(flowQueue);
1138
+ await flowQueue.awaitCompletion();
1139
+ expect(flowQueue.successOutputs.size).toBe(1);
1140
+ });
1141
+ it('应该支持 reset 方法的链式调用', async () => {
1142
+ const firstInput = { id: 1, data: 'first' };
1143
+ const secondInput = { id: 2, data: 'second' };
1144
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1145
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1146
+ });
1147
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1148
+ // 第一轮处理
1149
+ flowQueue.input(firstInput);
1150
+ flowQueue.closeInput();
1151
+ await flowQueue.awaitCompletion();
1152
+ expect(flowQueue.successOutputs.size).toBe(1);
1153
+ // 测试链式调用重置并开始新处理
1154
+ const returnValue = flowQueue
1155
+ .reset()
1156
+ .input(secondInput)
1157
+ .closeInput();
1158
+ expect(returnValue).toBe(flowQueue);
1159
+ await flowQueue.awaitCompletion();
1160
+ expect(flowQueue.successOutputs.size).toBe(1);
1161
+ expect(flowQueue.successOutputs.get(secondInput)?.result).toBe('processed_second');
1162
+ });
1163
+ it('应该支持 cancel 方法的链式调用', async () => {
1164
+ const testInputs = [
1165
+ { id: 1, data: 'test1' },
1166
+ { id: 2, data: 'test2' }
1167
+ ];
1168
+ flowQueue.input(...testInputs);
1169
+ // 测试链式调用
1170
+ const returnValue = flowQueue.cancel();
1171
+ expect(returnValue).toBe(flowQueue);
1172
+ expect(flowQueue['pendingInputs'].length).toBe(0);
1173
+ // 等待异步完成状态更新
1174
+ await new Promise(resolve => setTimeout(resolve, 10));
1175
+ expect(flowQueue.isCompleted).toBe(true);
1176
+ });
1177
+ it('应该支持完整的链式调用流程', async () => {
1178
+ const inputs = [
1179
+ { id: 1, data: 'test1' },
1180
+ { id: 2, data: 'test2' },
1181
+ { id: 3, data: 'test3' }
1182
+ ];
1183
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1184
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1185
+ });
1186
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1187
+ // 测试完整的链式调用流程
1188
+ await flowQueue
1189
+ .input(inputs[0], inputs[1])
1190
+ .input(inputs[2])
1191
+ .closeInput()
1192
+ .awaitCompletion();
1193
+ expect(flowQueue.successOutputs.size).toBe(3);
1194
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
1195
+ // 测试重置后的链式调用
1196
+ await flowQueue
1197
+ .reset()
1198
+ .input(inputs[0])
1199
+ .closeInput()
1200
+ .awaitCompletion();
1201
+ expect(flowQueue.successOutputs.size).toBe(1);
1202
+ });
1203
+ });
1033
1204
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taicode/common-base",
3
- "version": "1.7.3",
3
+ "version": "1.7.4",
4
4
  "author": "Alain",
5
5
  "license": "ISC",
6
6
  "description": "",
@@ -1,6 +0,0 @@
1
- export declare class Disposer {
2
- private cleanupFunctions;
3
- addDisposer(cleanupFn: () => unknown): void;
4
- dispose(): void;
5
- }
6
- //# sourceMappingURL=disposer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"disposer.d.ts","sourceRoot":"","sources":["../../source/events/disposer.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ;IACnB,OAAO,CAAC,gBAAgB,CAAyB;IAGjD,WAAW,CAAC,SAAS,EAAE,MAAM,OAAO,GAAG,IAAI;IAK3C,OAAO,IAAI,IAAI;CAUhB"}
@@ -1,19 +0,0 @@
1
- export class Disposer {
2
- cleanupFunctions = [];
3
- // 添加清理函数
4
- addDisposer(cleanupFn) {
5
- this.cleanupFunctions.push(cleanupFn);
6
- }
7
- // 执行所有清理函数
8
- dispose() {
9
- for (const cleanupFn of this.cleanupFunctions) {
10
- try {
11
- cleanupFn();
12
- }
13
- catch (error) {
14
- console.error('Error during cleanup:', error);
15
- }
16
- }
17
- this.cleanupFunctions = []; // 清空清理函数列表
18
- }
19
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=disposer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"disposer.test.d.ts","sourceRoot":"","sources":["../../source/events/disposer.test.ts"],"names":[],"mappings":""}
@@ -1,192 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { Disposer } from './disposer';
3
- describe('Disposer', () => {
4
- let disposer;
5
- beforeEach(() => {
6
- disposer = new Disposer();
7
- });
8
- describe('addDisposer', () => {
9
- it('应该能够添加清理函数', () => {
10
- const cleanupFn = vi.fn();
11
- expect(() => {
12
- disposer.addDisposer(cleanupFn);
13
- }).not.toThrow();
14
- });
15
- it('应该能够添加多个清理函数', () => {
16
- const cleanupFn1 = vi.fn();
17
- const cleanupFn2 = vi.fn();
18
- const cleanupFn3 = vi.fn();
19
- disposer.addDisposer(cleanupFn1);
20
- disposer.addDisposer(cleanupFn2);
21
- disposer.addDisposer(cleanupFn3);
22
- disposer.dispose();
23
- expect(cleanupFn1).toHaveBeenCalledOnce();
24
- expect(cleanupFn2).toHaveBeenCalledOnce();
25
- expect(cleanupFn3).toHaveBeenCalledOnce();
26
- });
27
- it('应该能够添加返回不同类型的清理函数', () => {
28
- const voidFn = vi.fn(() => { });
29
- const stringFn = vi.fn(() => 'cleanup result');
30
- const numberFn = vi.fn(() => 42);
31
- const promiseFn = vi.fn(() => Promise.resolve('async cleanup'));
32
- disposer.addDisposer(voidFn);
33
- disposer.addDisposer(stringFn);
34
- disposer.addDisposer(numberFn);
35
- disposer.addDisposer(promiseFn);
36
- disposer.dispose();
37
- expect(voidFn).toHaveBeenCalled();
38
- expect(stringFn).toHaveBeenCalled();
39
- expect(numberFn).toHaveBeenCalled();
40
- expect(promiseFn).toHaveBeenCalled();
41
- });
42
- });
43
- describe('dispose', () => {
44
- it('应该执行所有清理函数', () => {
45
- const cleanupFn1 = vi.fn();
46
- const cleanupFn2 = vi.fn();
47
- const cleanupFn3 = vi.fn();
48
- disposer.addDisposer(cleanupFn1);
49
- disposer.addDisposer(cleanupFn2);
50
- disposer.addDisposer(cleanupFn3);
51
- disposer.dispose();
52
- expect(cleanupFn1).toHaveBeenCalledOnce();
53
- expect(cleanupFn2).toHaveBeenCalledOnce();
54
- expect(cleanupFn3).toHaveBeenCalledOnce();
55
- });
56
- it('应该按添加顺序执行清理函数', () => {
57
- const executionOrder = [];
58
- disposer.addDisposer(() => executionOrder.push(1));
59
- disposer.addDisposer(() => executionOrder.push(2));
60
- disposer.addDisposer(() => executionOrder.push(3));
61
- disposer.dispose();
62
- expect(executionOrder).toEqual([1, 2, 3]);
63
- });
64
- it('应该处理清理函数中的错误', () => {
65
- const workingFn1 = vi.fn();
66
- const errorFn = vi.fn(() => {
67
- throw new Error('Cleanup error');
68
- });
69
- const workingFn2 = vi.fn();
70
- // 模拟 console.error
71
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
72
- disposer.addDisposer(workingFn1);
73
- disposer.addDisposer(errorFn);
74
- disposer.addDisposer(workingFn2);
75
- // dispose 不应该抛出错误
76
- expect(() => {
77
- disposer.dispose();
78
- }).not.toThrow();
79
- // 所有函数都应该被调用
80
- expect(workingFn1).toHaveBeenCalled();
81
- expect(errorFn).toHaveBeenCalled();
82
- expect(workingFn2).toHaveBeenCalled();
83
- // 错误应该被记录
84
- expect(consoleSpy).toHaveBeenCalledWith('Error during cleanup:', expect.any(Error));
85
- consoleSpy.mockRestore();
86
- });
87
- it('应该在执行后清空清理函数列表', () => {
88
- const cleanupFn = vi.fn();
89
- disposer.addDisposer(cleanupFn);
90
- disposer.dispose();
91
- expect(cleanupFn).toHaveBeenCalledOnce();
92
- // 再次调用 dispose 不应该执行任何函数
93
- disposer.dispose();
94
- expect(cleanupFn).toHaveBeenCalledOnce();
95
- });
96
- it('应该能够在清空后重新添加清理函数', () => {
97
- const firstCleanup = vi.fn();
98
- const secondCleanup = vi.fn();
99
- disposer.addDisposer(firstCleanup);
100
- disposer.dispose();
101
- disposer.addDisposer(secondCleanup);
102
- disposer.dispose();
103
- expect(firstCleanup).toHaveBeenCalledOnce();
104
- expect(secondCleanup).toHaveBeenCalledOnce();
105
- });
106
- it('应该在没有清理函数时安全执行', () => {
107
- expect(() => {
108
- disposer.dispose();
109
- }).not.toThrow();
110
- });
111
- it('应该能够多次调用 dispose', () => {
112
- const cleanupFn = vi.fn();
113
- disposer.addDisposer(cleanupFn);
114
- disposer.dispose();
115
- disposer.dispose();
116
- disposer.dispose();
117
- expect(cleanupFn).toHaveBeenCalledOnce();
118
- });
119
- });
120
- describe('实际使用场景', () => {
121
- it('应该能够清理事件监听器', () => {
122
- const removeEventListener = vi.fn();
123
- const unsubscribe = vi.fn();
124
- disposer.addDisposer(removeEventListener);
125
- disposer.addDisposer(unsubscribe);
126
- disposer.dispose();
127
- expect(removeEventListener).toHaveBeenCalled();
128
- expect(unsubscribe).toHaveBeenCalled();
129
- });
130
- it('应该能够清理定时器', () => {
131
- const clearTimeout = vi.fn();
132
- const clearInterval = vi.fn();
133
- disposer.addDisposer(() => clearTimeout(123));
134
- disposer.addDisposer(() => clearInterval(456));
135
- disposer.dispose();
136
- expect(clearTimeout).toHaveBeenCalledWith(123);
137
- expect(clearInterval).toHaveBeenCalledWith(456);
138
- });
139
- it('应该能够清理资源连接', () => {
140
- const closeConnection = vi.fn();
141
- const releaseResource = vi.fn();
142
- disposer.addDisposer(() => closeConnection());
143
- disposer.addDisposer(() => releaseResource());
144
- disposer.dispose();
145
- expect(closeConnection).toHaveBeenCalled();
146
- expect(releaseResource).toHaveBeenCalled();
147
- });
148
- it('应该与 EventEmitter 配合使用', () => {
149
- // 模拟 EventEmitter 的使用
150
- const mockEventEmitter = {
151
- on: vi.fn().mockReturnValue(vi.fn()), // 返回 off 函数
152
- cleanup: vi.fn()
153
- };
154
- const offFunction1 = mockEventEmitter.on('event1', vi.fn());
155
- const offFunction2 = mockEventEmitter.on('event2', vi.fn());
156
- disposer.addDisposer(offFunction1);
157
- disposer.addDisposer(offFunction2);
158
- disposer.addDisposer(() => mockEventEmitter.cleanup());
159
- disposer.dispose();
160
- expect(offFunction1).toHaveBeenCalled();
161
- expect(offFunction2).toHaveBeenCalled();
162
- expect(mockEventEmitter.cleanup).toHaveBeenCalled();
163
- });
164
- });
165
- describe('错误处理', () => {
166
- it('应该捕获并记录同步错误', () => {
167
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
168
- const error = new Error('Sync error');
169
- disposer.addDisposer(() => {
170
- throw error;
171
- });
172
- disposer.dispose();
173
- expect(consoleSpy).toHaveBeenCalledWith('Error during cleanup:', error);
174
- consoleSpy.mockRestore();
175
- });
176
- it('应该处理不同类型的错误', () => {
177
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
178
- disposer.addDisposer(() => {
179
- throw new TypeError('Type error');
180
- });
181
- disposer.addDisposer(() => {
182
- throw 'String error';
183
- });
184
- disposer.addDisposer(() => {
185
- throw { message: 'Object error' };
186
- });
187
- disposer.dispose();
188
- expect(consoleSpy).toHaveBeenCalledTimes(3);
189
- consoleSpy.mockRestore();
190
- });
191
- });
192
- });
@@ -1,33 +0,0 @@
1
- type OffFn = () => void;
2
- type Listener<T = unknown> = (data: T) => void;
3
- export declare class EventEmitter<Events extends object = object> {
4
- private listeners;
5
- constructor();
6
- /**
7
- * 订阅事件
8
- * @param type 事件类型
9
- * @param listener 回调函数
10
- */
11
- on<K extends keyof Events>(type: K, listener: Listener<Events[K]>): OffFn;
12
- /**
13
- * 取消订阅
14
- * @param type 事件类型
15
- * @param listener 要移除的回调函数(可选)
16
- */
17
- off<K extends keyof Events>(type: K, listener?: Listener<Events[K]>): void;
18
- /**
19
- * 触发事件
20
- * @param type 事件类型
21
- * @param data 要传递的数据
22
- */
23
- emit<K extends keyof Events>(type: K, data: Events[K]): void;
24
- /**
25
- * 一次性订阅
26
- * @param type 事件类型
27
- * @param listener 回调函数
28
- */
29
- once<K extends keyof Events>(type: K, listener: Listener<Events[K]>): void;
30
- cleanup(): void;
31
- }
32
- export {};
33
- //# sourceMappingURL=event-emitter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../../source/events/event-emitter.ts"],"names":[],"mappings":"AAAA,KAAK,KAAK,GAAG,MAAM,IAAI,CAAA;AACvB,KAAK,QAAQ,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;AAE9C,qBAAa,YAAY,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IACtD,OAAO,CAAC,SAAS,CAAsD;;IAUvE;;;;OAIG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;IASzE;;;;OAIG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAc1E;;;;OAIG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAQ5D;;;;OAIG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAQ1E,OAAO;CAGR"}
@@ -1,66 +0,0 @@
1
- export class EventEmitter {
2
- listeners = {};
3
- constructor() {
4
- this.on = this.on.bind(this);
5
- this.off = this.off.bind(this);
6
- this.once = this.once.bind(this);
7
- this.emit = this.emit.bind(this);
8
- this.cleanup = this.cleanup.bind(this);
9
- }
10
- /**
11
- * 订阅事件
12
- * @param type 事件类型
13
- * @param listener 回调函数
14
- */
15
- on(type, listener) {
16
- if (!this.listeners[type]) {
17
- this.listeners[type] = [];
18
- }
19
- this.listeners[type].push(listener);
20
- return () => this.off(type, listener);
21
- }
22
- /**
23
- * 取消订阅
24
- * @param type 事件类型
25
- * @param listener 要移除的回调函数(可选)
26
- */
27
- off(type, listener) {
28
- if (!this.listeners[type])
29
- return;
30
- if (!listener) {
31
- // 移除该事件的所有监听器
32
- delete this.listeners[type];
33
- }
34
- else {
35
- // 移除特定监听器
36
- this.listeners[type] = this.listeners[type].filter((fn) => fn !== listener);
37
- }
38
- }
39
- /**
40
- * 触发事件
41
- * @param type 事件类型
42
- * @param data 要传递的数据
43
- */
44
- emit(type, data) {
45
- const listeners = this.listeners[type];
46
- // 复制数组避免回调中取消订阅导致的遍历问题
47
- if (listeners) {
48
- listeners.slice().forEach((fn) => fn(data));
49
- }
50
- }
51
- /**
52
- * 一次性订阅
53
- * @param type 事件类型
54
- * @param listener 回调函数
55
- */
56
- once(type, listener) {
57
- const onceWrapper = (data) => {
58
- listener(data);
59
- this.off(type, onceWrapper);
60
- };
61
- this.on(type, onceWrapper);
62
- }
63
- cleanup() {
64
- this.listeners = {};
65
- }
66
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=event-emitter.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-emitter.test.d.ts","sourceRoot":"","sources":["../../source/events/event-emitter.test.ts"],"names":[],"mappings":""}