@taicode/common-base 1.7.1 → 1.7.3
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/output/batching-buffer/batching-buffer.d.ts +10 -17
- package/output/batching-buffer/batching-buffer.d.ts.map +1 -1
- package/output/batching-buffer/batching-buffer.js +37 -46
- package/output/batching-buffer/batching-buffer.test.js +8 -161
- package/output/events/disposer.d.ts +6 -0
- package/output/events/disposer.d.ts.map +1 -0
- package/output/events/disposer.js +19 -0
- package/output/events/disposer.test.d.ts +2 -0
- package/output/events/disposer.test.d.ts.map +1 -0
- package/output/events/disposer.test.js +192 -0
- package/output/events/event-emitter.d.ts +33 -0
- package/output/events/event-emitter.d.ts.map +1 -0
- package/output/events/event-emitter.js +66 -0
- package/output/events/event-emitter.test.d.ts +2 -0
- package/output/events/event-emitter.test.d.ts.map +1 -0
- package/output/events/event-emitter.test.js +213 -0
- package/output/events/index.d.ts +3 -0
- package/output/events/index.d.ts.map +1 -0
- package/output/events/index.js +3 -0
- package/output/flow-queue/flow-queue.d.ts +418 -0
- package/output/flow-queue/flow-queue.d.ts.map +1 -0
- package/output/flow-queue/flow-queue.js +582 -0
- package/output/flow-queue/flow-queue.test.d.ts +2 -0
- package/output/flow-queue/flow-queue.test.d.ts.map +1 -0
- package/output/flow-queue/flow-queue.test.js +1033 -0
- package/output/flow-queue/index.d.ts +3 -0
- package/output/flow-queue/index.d.ts.map +1 -0
- package/output/flow-queue/index.js +3 -0
- package/output/index.d.ts +2 -0
- package/output/index.d.ts.map +1 -1
- package/output/index.js +2 -0
- package/output/logger/logger.d.ts +3 -3
- package/output/logger/logger.d.ts.map +1 -1
- package/output/logger/logger.js +2 -3
- package/output/logger/logger.test.js +1 -1
- package/output/ttl-cache/index.d.ts +2 -0
- package/output/ttl-cache/index.d.ts.map +1 -0
- package/output/ttl-cache/index.js +1 -0
- package/output/ttl-cache/ttl-cache.d.ts +148 -0
- package/output/ttl-cache/ttl-cache.d.ts.map +1 -0
- package/output/ttl-cache/ttl-cache.js +313 -0
- package/output/ttl-cache/ttl-cache.test.d.ts +2 -0
- package/output/ttl-cache/ttl-cache.test.d.ts.map +1 -0
- package/output/ttl-cache/ttl-cache.test.js +222 -0
- package/package.json +1 -1
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"event-emitter.test.d.ts","sourceRoot":"","sources":["../../source/events/event-emitter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { EventEmitter } from './event-emitter';
|
|
3
|
+
describe('EventEmitter', () => {
|
|
4
|
+
let emitter;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
emitter = new EventEmitter();
|
|
7
|
+
});
|
|
8
|
+
describe('on', () => {
|
|
9
|
+
it('应该能够订阅事件', () => {
|
|
10
|
+
const listener = vi.fn();
|
|
11
|
+
emitter.on('test', listener);
|
|
12
|
+
emitter.emit('test', 'hello');
|
|
13
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
14
|
+
expect(listener).toHaveBeenCalledWith('hello');
|
|
15
|
+
});
|
|
16
|
+
it('应该能够订阅多个监听器', () => {
|
|
17
|
+
const listener1 = vi.fn();
|
|
18
|
+
const listener2 = vi.fn();
|
|
19
|
+
emitter.on('test', listener1);
|
|
20
|
+
emitter.on('test', listener2);
|
|
21
|
+
emitter.emit('test', 'hello');
|
|
22
|
+
expect(listener1).toHaveBeenCalledOnce();
|
|
23
|
+
expect(listener2).toHaveBeenCalledOnce();
|
|
24
|
+
expect(listener1).toHaveBeenCalledWith('hello');
|
|
25
|
+
expect(listener2).toHaveBeenCalledWith('hello');
|
|
26
|
+
});
|
|
27
|
+
it('应该返回取消订阅函数', () => {
|
|
28
|
+
const listener = vi.fn();
|
|
29
|
+
const off = emitter.on('test', listener);
|
|
30
|
+
emitter.emit('test', 'hello');
|
|
31
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
32
|
+
off();
|
|
33
|
+
emitter.emit('test', 'world');
|
|
34
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
35
|
+
});
|
|
36
|
+
it('应该支持不同类型的事件数据', () => {
|
|
37
|
+
const stringListener = vi.fn();
|
|
38
|
+
const numberListener = vi.fn();
|
|
39
|
+
const objectListener = vi.fn();
|
|
40
|
+
const voidListener = vi.fn();
|
|
41
|
+
emitter.on('test', stringListener);
|
|
42
|
+
emitter.on('number', numberListener);
|
|
43
|
+
emitter.on('object', objectListener);
|
|
44
|
+
emitter.on('noData', voidListener);
|
|
45
|
+
const testObject = { id: 1, name: 'test' };
|
|
46
|
+
emitter.emit('test', 'hello');
|
|
47
|
+
emitter.emit('number', 42);
|
|
48
|
+
emitter.emit('object', testObject);
|
|
49
|
+
emitter.emit('noData', undefined);
|
|
50
|
+
expect(stringListener).toHaveBeenCalledWith('hello');
|
|
51
|
+
expect(numberListener).toHaveBeenCalledWith(42);
|
|
52
|
+
expect(objectListener).toHaveBeenCalledWith(testObject);
|
|
53
|
+
expect(voidListener).toHaveBeenCalledWith(undefined);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('off', () => {
|
|
57
|
+
it('应该能够取消订阅特定监听器', () => {
|
|
58
|
+
const listener1 = vi.fn();
|
|
59
|
+
const listener2 = vi.fn();
|
|
60
|
+
emitter.on('test', listener1);
|
|
61
|
+
emitter.on('test', listener2);
|
|
62
|
+
emitter.off('test', listener1);
|
|
63
|
+
emitter.emit('test', 'hello');
|
|
64
|
+
expect(listener1).not.toHaveBeenCalled();
|
|
65
|
+
expect(listener2).toHaveBeenCalledOnce();
|
|
66
|
+
});
|
|
67
|
+
it('应该能够取消订阅所有监听器', () => {
|
|
68
|
+
const listener1 = vi.fn();
|
|
69
|
+
const listener2 = vi.fn();
|
|
70
|
+
emitter.on('test', listener1);
|
|
71
|
+
emitter.on('test', listener2);
|
|
72
|
+
emitter.off('test');
|
|
73
|
+
emitter.emit('test', 'hello');
|
|
74
|
+
expect(listener1).not.toHaveBeenCalled();
|
|
75
|
+
expect(listener2).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
it('应该忽略不存在的事件类型', () => {
|
|
78
|
+
expect(() => {
|
|
79
|
+
emitter.off('test');
|
|
80
|
+
}).not.toThrow();
|
|
81
|
+
});
|
|
82
|
+
it('应该忽略不存在的监听器', () => {
|
|
83
|
+
const listener = vi.fn();
|
|
84
|
+
const anotherListener = vi.fn();
|
|
85
|
+
emitter.on('test', listener);
|
|
86
|
+
expect(() => {
|
|
87
|
+
emitter.off('test', anotherListener);
|
|
88
|
+
}).not.toThrow();
|
|
89
|
+
emitter.emit('test', 'hello');
|
|
90
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('emit', () => {
|
|
94
|
+
it('应该能够触发事件', () => {
|
|
95
|
+
const listener = vi.fn();
|
|
96
|
+
emitter.on('test', listener);
|
|
97
|
+
emitter.emit('test', 'hello');
|
|
98
|
+
expect(listener).toHaveBeenCalledWith('hello');
|
|
99
|
+
});
|
|
100
|
+
it('应该不抛出错误当没有监听器时', () => {
|
|
101
|
+
expect(() => {
|
|
102
|
+
emitter.emit('test', 'hello');
|
|
103
|
+
}).not.toThrow();
|
|
104
|
+
});
|
|
105
|
+
it('应该按顺序调用监听器', () => {
|
|
106
|
+
const calls = [];
|
|
107
|
+
emitter.on('test', () => calls.push(1));
|
|
108
|
+
emitter.on('test', () => calls.push(2));
|
|
109
|
+
emitter.on('test', () => calls.push(3));
|
|
110
|
+
emitter.emit('test', 'hello');
|
|
111
|
+
expect(calls).toEqual([1, 2, 3]);
|
|
112
|
+
});
|
|
113
|
+
it('应该处理监听器中的错误', () => {
|
|
114
|
+
const workingListener = vi.fn();
|
|
115
|
+
const errorListener = vi.fn(() => {
|
|
116
|
+
throw new Error('Test error');
|
|
117
|
+
});
|
|
118
|
+
const anotherWorkingListener = vi.fn();
|
|
119
|
+
emitter.on('test', workingListener);
|
|
120
|
+
emitter.on('test', errorListener);
|
|
121
|
+
emitter.on('test', anotherWorkingListener);
|
|
122
|
+
expect(() => {
|
|
123
|
+
emitter.emit('test', 'hello');
|
|
124
|
+
}).toThrow('Test error');
|
|
125
|
+
expect(workingListener).toHaveBeenCalled();
|
|
126
|
+
expect(errorListener).toHaveBeenCalled();
|
|
127
|
+
// 由于错误,后续监听器可能不会被调用
|
|
128
|
+
});
|
|
129
|
+
it('应该防止监听器修改监听器列表时的遍历问题', () => {
|
|
130
|
+
const listener1 = vi.fn();
|
|
131
|
+
const listener2 = vi.fn(() => {
|
|
132
|
+
// 在回调中取消订阅
|
|
133
|
+
emitter.off('test', listener3);
|
|
134
|
+
});
|
|
135
|
+
const listener3 = vi.fn();
|
|
136
|
+
emitter.on('test', listener1);
|
|
137
|
+
emitter.on('test', listener2);
|
|
138
|
+
emitter.on('test', listener3);
|
|
139
|
+
emitter.emit('test', 'hello');
|
|
140
|
+
expect(listener1).toHaveBeenCalled();
|
|
141
|
+
expect(listener2).toHaveBeenCalled();
|
|
142
|
+
expect(listener3).toHaveBeenCalled(); // 应该仍然被调用,因为使用了 slice()
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('once', () => {
|
|
146
|
+
it('应该只执行一次监听器', () => {
|
|
147
|
+
const listener = vi.fn();
|
|
148
|
+
emitter.once('test', listener);
|
|
149
|
+
emitter.emit('test', 'first');
|
|
150
|
+
emitter.emit('test', 'second');
|
|
151
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
152
|
+
expect(listener).toHaveBeenCalledWith('first');
|
|
153
|
+
});
|
|
154
|
+
it('应该在执行后自动取消订阅', () => {
|
|
155
|
+
const listener = vi.fn();
|
|
156
|
+
emitter.once('test', listener);
|
|
157
|
+
emitter.emit('test', 'hello');
|
|
158
|
+
// 验证监听器已被移除
|
|
159
|
+
emitter.emit('test', 'world');
|
|
160
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
161
|
+
});
|
|
162
|
+
it('应该与普通监听器一起工作', () => {
|
|
163
|
+
const onceListener = vi.fn();
|
|
164
|
+
const normalListener = vi.fn();
|
|
165
|
+
emitter.once('test', onceListener);
|
|
166
|
+
emitter.on('test', normalListener);
|
|
167
|
+
emitter.emit('test', 'first');
|
|
168
|
+
emitter.emit('test', 'second');
|
|
169
|
+
expect(onceListener).toHaveBeenCalledOnce();
|
|
170
|
+
expect(normalListener).toHaveBeenCalledTimes(2);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('cleanup', () => {
|
|
174
|
+
it('应该清空所有监听器', () => {
|
|
175
|
+
const listener1 = vi.fn();
|
|
176
|
+
const listener2 = vi.fn();
|
|
177
|
+
emitter.on('test', listener1);
|
|
178
|
+
emitter.on('number', listener2);
|
|
179
|
+
emitter.cleanup();
|
|
180
|
+
emitter.emit('test', 'hello');
|
|
181
|
+
emitter.emit('number', 42);
|
|
182
|
+
expect(listener1).not.toHaveBeenCalled();
|
|
183
|
+
expect(listener2).not.toHaveBeenCalled();
|
|
184
|
+
});
|
|
185
|
+
it('清理后应该能够重新添加监听器', () => {
|
|
186
|
+
const listener = vi.fn();
|
|
187
|
+
emitter.on('test', listener);
|
|
188
|
+
emitter.cleanup();
|
|
189
|
+
const newListener = vi.fn();
|
|
190
|
+
emitter.on('test', newListener);
|
|
191
|
+
emitter.emit('test', 'hello');
|
|
192
|
+
expect(listener).not.toHaveBeenCalled();
|
|
193
|
+
expect(newListener).toHaveBeenCalledWith('hello');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('方法绑定', () => {
|
|
197
|
+
it('方法应该绑定到实例', () => {
|
|
198
|
+
const { on, off, emit, once, cleanup } = emitter;
|
|
199
|
+
const listener = vi.fn();
|
|
200
|
+
on('test', listener);
|
|
201
|
+
emit('test', 'hello');
|
|
202
|
+
expect(listener).toHaveBeenCalledWith('hello');
|
|
203
|
+
off('test', listener);
|
|
204
|
+
emit('test', 'world');
|
|
205
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
206
|
+
// 测试其他方法
|
|
207
|
+
once('test', listener);
|
|
208
|
+
emit('test', 'once');
|
|
209
|
+
expect(listener).toHaveBeenCalledTimes(2);
|
|
210
|
+
cleanup();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/events/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA"}
|