@taicode/common-base 3.1.0 → 3.1.1

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.
@@ -1,6 +1,8 @@
1
+ type CleanupFunction = () => unknown | Promise<unknown>;
1
2
  export declare class Disposer {
2
3
  private cleanupFunctions;
3
- addDisposer(cleanupFn: () => unknown): void;
4
- dispose(): void;
4
+ addDisposer(cleanupFn: CleanupFunction): void;
5
+ dispose(): Promise<void>;
5
6
  }
7
+ export {};
6
8
  //# sourceMappingURL=disposer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"disposer.d.ts","sourceRoot":"","sources":["../../source/disposer/disposer.ts"],"names":[],"mappings":"AAEA,qBAAa,QAAQ;IACnB,OAAO,CAAC,gBAAgB,CAAyB;IAGjD,WAAW,CAAC,SAAS,EAAE,MAAM,OAAO,GAAG,IAAI;IAK3C,OAAO,IAAI,IAAI;CAUhB"}
1
+ {"version":3,"file":"disposer.d.ts","sourceRoot":"","sources":["../../source/disposer/disposer.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,GAAG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;AAEvD,qBAAa,QAAQ;IACnB,OAAO,CAAC,gBAAgB,CAAwB;IAGhD,WAAW,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI;IAKvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAY/B"}
@@ -6,15 +6,16 @@ export class Disposer {
6
6
  this.cleanupFunctions.push(cleanupFn);
7
7
  }
8
8
  // 执行所有清理函数
9
- dispose() {
10
- for (const cleanupFn of this.cleanupFunctions) {
9
+ async dispose() {
10
+ const cleanupFunctions = this.cleanupFunctions;
11
+ this.cleanupFunctions = [];
12
+ for (const cleanupFn of cleanupFunctions) {
11
13
  try {
12
- cleanupFn();
14
+ await cleanupFn();
13
15
  }
14
16
  catch (error) {
15
17
  logger.error('Error during cleanup:', error);
16
18
  }
17
19
  }
18
- this.cleanupFunctions = []; // 清空清理函数列表
19
20
  }
20
21
  }
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import { Disposer } from './disposer.js';
3
+ import { logger } from '../logger/index.js';
3
4
  describe('Disposer', () => {
4
5
  let disposer;
5
6
  beforeEach(() => {
@@ -12,19 +13,19 @@ describe('Disposer', () => {
12
13
  disposer.addDisposer(cleanupFn);
13
14
  }).not.toThrow();
14
15
  });
15
- it('应该能够添加多个清理函数', () => {
16
+ it('应该能够添加多个清理函数', async () => {
16
17
  const cleanupFn1 = vi.fn();
17
18
  const cleanupFn2 = vi.fn();
18
19
  const cleanupFn3 = vi.fn();
19
20
  disposer.addDisposer(cleanupFn1);
20
21
  disposer.addDisposer(cleanupFn2);
21
22
  disposer.addDisposer(cleanupFn3);
22
- disposer.dispose();
23
+ await disposer.dispose();
23
24
  expect(cleanupFn1).toHaveBeenCalledOnce();
24
25
  expect(cleanupFn2).toHaveBeenCalledOnce();
25
26
  expect(cleanupFn3).toHaveBeenCalledOnce();
26
27
  });
27
- it('应该能够添加返回不同类型的清理函数', () => {
28
+ it('应该能够添加返回不同类型的清理函数', async () => {
28
29
  const voidFn = vi.fn(() => { });
29
30
  const stringFn = vi.fn(() => 'cleanup result');
30
31
  const numberFn = vi.fn(() => 42);
@@ -33,7 +34,7 @@ describe('Disposer', () => {
33
34
  disposer.addDisposer(stringFn);
34
35
  disposer.addDisposer(numberFn);
35
36
  disposer.addDisposer(promiseFn);
36
- disposer.dispose();
37
+ await disposer.dispose();
37
38
  expect(voidFn).toHaveBeenCalled();
38
39
  expect(stringFn).toHaveBeenCalled();
39
40
  expect(numberFn).toHaveBeenCalled();
@@ -41,111 +42,124 @@ describe('Disposer', () => {
41
42
  });
42
43
  });
43
44
  describe('dispose', () => {
44
- it('应该执行所有清理函数', () => {
45
+ it('应该执行所有清理函数', async () => {
45
46
  const cleanupFn1 = vi.fn();
46
47
  const cleanupFn2 = vi.fn();
47
48
  const cleanupFn3 = vi.fn();
48
49
  disposer.addDisposer(cleanupFn1);
49
50
  disposer.addDisposer(cleanupFn2);
50
51
  disposer.addDisposer(cleanupFn3);
51
- disposer.dispose();
52
+ await disposer.dispose();
52
53
  expect(cleanupFn1).toHaveBeenCalledOnce();
53
54
  expect(cleanupFn2).toHaveBeenCalledOnce();
54
55
  expect(cleanupFn3).toHaveBeenCalledOnce();
55
56
  });
56
- it('应该按添加顺序执行清理函数', () => {
57
+ it('应该按添加顺序执行清理函数', async () => {
57
58
  const executionOrder = [];
58
59
  disposer.addDisposer(() => executionOrder.push(1));
59
60
  disposer.addDisposer(() => executionOrder.push(2));
60
61
  disposer.addDisposer(() => executionOrder.push(3));
61
- disposer.dispose();
62
+ await disposer.dispose();
62
63
  expect(executionOrder).toEqual([1, 2, 3]);
63
64
  });
64
- it('应该处理清理函数中的错误', () => {
65
+ it('应该按添加顺序执行异步清理函数', async () => {
66
+ const executionOrder = [];
67
+ disposer.addDisposer(async () => {
68
+ await Promise.resolve();
69
+ executionOrder.push(1);
70
+ });
71
+ disposer.addDisposer(async () => {
72
+ await Promise.resolve();
73
+ executionOrder.push(2);
74
+ });
75
+ disposer.addDisposer(async () => {
76
+ await Promise.resolve();
77
+ executionOrder.push(3);
78
+ });
79
+ await disposer.dispose();
80
+ expect(executionOrder).toEqual([1, 2, 3]);
81
+ });
82
+ it('应该处理清理函数中的错误', async () => {
65
83
  const workingFn1 = vi.fn();
66
84
  const errorFn = vi.fn(() => {
67
85
  throw new Error('Cleanup error');
68
86
  });
69
87
  const workingFn2 = vi.fn();
70
- // 模拟 console.error
71
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
88
+ // 模拟 logger.error
89
+ const loggerErrorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
72
90
  disposer.addDisposer(workingFn1);
73
91
  disposer.addDisposer(errorFn);
74
92
  disposer.addDisposer(workingFn2);
75
93
  // dispose 不应该抛出错误
76
- expect(() => {
77
- disposer.dispose();
78
- }).not.toThrow();
94
+ await expect(disposer.dispose()).resolves.toBeUndefined();
79
95
  // 所有函数都应该被调用
80
96
  expect(workingFn1).toHaveBeenCalled();
81
97
  expect(errorFn).toHaveBeenCalled();
82
98
  expect(workingFn2).toHaveBeenCalled();
83
99
  // 错误应该被记录
84
- expect(consoleSpy).toHaveBeenCalledWith('Error during cleanup:', expect.any(Error));
85
- consoleSpy.mockRestore();
100
+ expect(loggerErrorSpy).toHaveBeenCalledWith('Error during cleanup:', expect.any(Error));
101
+ loggerErrorSpy.mockRestore();
86
102
  });
87
- it('应该在执行后清空清理函数列表', () => {
103
+ it('应该在执行后清空清理函数列表', async () => {
88
104
  const cleanupFn = vi.fn();
89
105
  disposer.addDisposer(cleanupFn);
90
- disposer.dispose();
106
+ await disposer.dispose();
91
107
  expect(cleanupFn).toHaveBeenCalledOnce();
92
108
  // 再次调用 dispose 不应该执行任何函数
93
- disposer.dispose();
109
+ await disposer.dispose();
94
110
  expect(cleanupFn).toHaveBeenCalledOnce();
95
111
  });
96
- it('应该能够在清空后重新添加清理函数', () => {
112
+ it('应该能够在清空后重新添加清理函数', async () => {
97
113
  const firstCleanup = vi.fn();
98
114
  const secondCleanup = vi.fn();
99
115
  disposer.addDisposer(firstCleanup);
100
- disposer.dispose();
116
+ await disposer.dispose();
101
117
  disposer.addDisposer(secondCleanup);
102
- disposer.dispose();
118
+ await disposer.dispose();
103
119
  expect(firstCleanup).toHaveBeenCalledOnce();
104
120
  expect(secondCleanup).toHaveBeenCalledOnce();
105
121
  });
106
- it('应该在没有清理函数时安全执行', () => {
107
- expect(() => {
108
- disposer.dispose();
109
- }).not.toThrow();
122
+ it('应该在没有清理函数时安全执行', async () => {
123
+ await expect(disposer.dispose()).resolves.toBeUndefined();
110
124
  });
111
- it('应该能够多次调用 dispose', () => {
125
+ it('应该能够多次调用 dispose', async () => {
112
126
  const cleanupFn = vi.fn();
113
127
  disposer.addDisposer(cleanupFn);
114
- disposer.dispose();
115
- disposer.dispose();
116
- disposer.dispose();
128
+ await disposer.dispose();
129
+ await disposer.dispose();
130
+ await disposer.dispose();
117
131
  expect(cleanupFn).toHaveBeenCalledOnce();
118
132
  });
119
133
  });
120
134
  describe('实际使用场景', () => {
121
- it('应该能够清理事件监听器', () => {
135
+ it('应该能够清理事件监听器', async () => {
122
136
  const removeEventListener = vi.fn();
123
137
  const unsubscribe = vi.fn();
124
138
  disposer.addDisposer(removeEventListener);
125
139
  disposer.addDisposer(unsubscribe);
126
- disposer.dispose();
140
+ await disposer.dispose();
127
141
  expect(removeEventListener).toHaveBeenCalled();
128
142
  expect(unsubscribe).toHaveBeenCalled();
129
143
  });
130
- it('应该能够清理定时器', () => {
144
+ it('应该能够清理定时器', async () => {
131
145
  const clearTimeout = vi.fn();
132
146
  const clearInterval = vi.fn();
133
147
  disposer.addDisposer(() => clearTimeout(123));
134
148
  disposer.addDisposer(() => clearInterval(456));
135
- disposer.dispose();
149
+ await disposer.dispose();
136
150
  expect(clearTimeout).toHaveBeenCalledWith(123);
137
151
  expect(clearInterval).toHaveBeenCalledWith(456);
138
152
  });
139
- it('应该能够清理资源连接', () => {
153
+ it('应该能够清理资源连接', async () => {
140
154
  const closeConnection = vi.fn();
141
155
  const releaseResource = vi.fn();
142
156
  disposer.addDisposer(() => closeConnection());
143
157
  disposer.addDisposer(() => releaseResource());
144
- disposer.dispose();
158
+ await disposer.dispose();
145
159
  expect(closeConnection).toHaveBeenCalled();
146
160
  expect(releaseResource).toHaveBeenCalled();
147
161
  });
148
- it('应该与 EventEmitter 配合使用', () => {
162
+ it('应该与 EventEmitter 配合使用', async () => {
149
163
  // 模拟 EventEmitter 的使用
150
164
  const mockEventEmitter = {
151
165
  on: vi.fn().mockReturnValue(vi.fn()), // 返回 off 函数
@@ -156,25 +170,25 @@ describe('Disposer', () => {
156
170
  disposer.addDisposer(offFunction1);
157
171
  disposer.addDisposer(offFunction2);
158
172
  disposer.addDisposer(() => mockEventEmitter.cleanup());
159
- disposer.dispose();
173
+ await disposer.dispose();
160
174
  expect(offFunction1).toHaveBeenCalled();
161
175
  expect(offFunction2).toHaveBeenCalled();
162
176
  expect(mockEventEmitter.cleanup).toHaveBeenCalled();
163
177
  });
164
178
  });
165
179
  describe('错误处理', () => {
166
- it('应该捕获并记录同步错误', () => {
167
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
180
+ it('应该捕获并记录同步错误', async () => {
181
+ const loggerErrorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
168
182
  const error = new Error('Sync error');
169
183
  disposer.addDisposer(() => {
170
184
  throw error;
171
185
  });
172
- disposer.dispose();
173
- expect(consoleSpy).toHaveBeenCalledWith('Error during cleanup:', error);
174
- consoleSpy.mockRestore();
186
+ await disposer.dispose();
187
+ expect(loggerErrorSpy).toHaveBeenCalledWith('Error during cleanup:', error);
188
+ loggerErrorSpy.mockRestore();
175
189
  });
176
- it('应该处理不同类型的错误', () => {
177
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
190
+ it('应该处理不同类型的错误', async () => {
191
+ const loggerErrorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
178
192
  disposer.addDisposer(() => {
179
193
  throw new TypeError('Type error');
180
194
  });
@@ -184,9 +198,19 @@ describe('Disposer', () => {
184
198
  disposer.addDisposer(() => {
185
199
  throw { message: 'Object error' };
186
200
  });
187
- disposer.dispose();
188
- expect(consoleSpy).toHaveBeenCalledTimes(3);
189
- consoleSpy.mockRestore();
201
+ await disposer.dispose();
202
+ expect(loggerErrorSpy).toHaveBeenCalledTimes(3);
203
+ loggerErrorSpy.mockRestore();
204
+ });
205
+ it('应该捕获并记录异步错误', async () => {
206
+ const loggerErrorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
207
+ const asyncError = new Error('Async error');
208
+ disposer.addDisposer(async () => {
209
+ throw asyncError;
210
+ });
211
+ await disposer.dispose();
212
+ expect(loggerErrorSpy).toHaveBeenCalledWith('Error during cleanup:', asyncError);
213
+ loggerErrorSpy.mockRestore();
190
214
  });
191
215
  });
192
216
  });
@@ -0,0 +1,6 @@
1
+ export declare class Disposer {
2
+ private cleanupFunctions;
3
+ addDisposer(cleanupFn: () => unknown): void;
4
+ dispose(): void;
5
+ }
6
+ //# sourceMappingURL=disposer.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,19 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=disposer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposer.test.d.ts","sourceRoot":"","sources":["../../source/events/disposer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,192 @@
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
+ });
@@ -0,0 +1,33 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,66 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-emitter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.test.d.ts","sourceRoot":"","sources":["../../source/events/event-emitter.test.ts"],"names":[],"mappings":""}