id-scanner-lib 1.3.3 → 1.5.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.md +55 -460
- package/dist/id-scanner-lib.esm.js +4641 -0
- package/dist/id-scanner-lib.esm.js.map +1 -0
- package/dist/id-scanner-lib.js +14755 -0
- package/dist/id-scanner-lib.js.map +1 -0
- package/dist/types/core/base-module.d.ts +44 -0
- package/dist/types/core/camera-manager.d.ts +258 -0
- package/dist/types/core/config.d.ts +88 -0
- package/dist/types/core/errors.d.ts +111 -0
- package/dist/types/core/event-emitter.d.ts +55 -0
- package/dist/types/core/logger.d.ts +277 -0
- package/dist/types/core/module-manager.d.ts +78 -0
- package/dist/types/core/plugin-manager.d.ts +158 -0
- package/dist/types/core/resource-manager.d.ts +246 -0
- package/dist/types/core/result.d.ts +83 -0
- package/dist/types/core/scanner-factory.d.ts +93 -0
- package/dist/types/index.bundle.d.ts +1303 -0
- package/dist/types/index.d.ts +86 -0
- package/dist/types/interfaces/external-types.d.ts +174 -0
- package/dist/types/interfaces/face-detection.d.ts +293 -0
- package/dist/types/interfaces/scanner-module.d.ts +280 -0
- package/dist/types/modules/face/face-detector.d.ts +170 -0
- package/dist/types/modules/face/index.d.ts +56 -0
- package/dist/types/modules/face/liveness-detector.d.ts +177 -0
- package/dist/types/modules/face/types.d.ts +136 -0
- package/dist/types/modules/id-card/anti-fake-detector.d.ts +170 -0
- package/dist/types/modules/id-card/id-card-detector.d.ts +131 -0
- package/dist/types/modules/id-card/index.d.ts +89 -0
- package/dist/types/modules/id-card/ocr-processor.d.ts +110 -0
- package/dist/types/modules/id-card/ocr-worker.d.ts +31 -0
- package/dist/types/modules/id-card/types.d.ts +181 -0
- package/dist/types/modules/qrcode/index.d.ts +51 -0
- package/dist/types/modules/qrcode/qr-code-scanner.d.ts +64 -0
- package/dist/types/modules/qrcode/types.d.ts +67 -0
- package/dist/types/utils/camera.d.ts +81 -0
- package/dist/types/utils/image-processing.d.ts +176 -0
- package/dist/types/utils/index.d.ts +175 -0
- package/dist/types/utils/performance.d.ts +81 -0
- package/dist/types/utils/resource-manager.d.ts +53 -0
- package/dist/types/utils/types.d.ts +166 -0
- package/dist/types/utils/worker.d.ts +52 -0
- package/dist/types/version.d.ts +7 -0
- package/package.json +76 -75
- package/src/core/base-module.ts +78 -0
- package/src/core/camera-manager.ts +798 -0
- package/src/core/config.ts +268 -0
- package/src/core/errors.ts +174 -0
- package/src/core/event-emitter.ts +110 -0
- package/src/core/logger.ts +549 -0
- package/src/core/module-manager.ts +165 -0
- package/src/core/plugin-manager.ts +429 -0
- package/src/core/resource-manager.ts +762 -0
- package/src/core/result.ts +163 -0
- package/src/core/scanner-factory.ts +237 -0
- package/src/index.ts +113 -936
- package/src/interfaces/external-types.ts +200 -0
- package/src/interfaces/face-detection.ts +309 -0
- package/src/interfaces/scanner-module.ts +384 -0
- package/src/modules/face/face-detector.ts +931 -0
- package/src/modules/face/index.ts +208 -0
- package/src/modules/face/liveness-detector.ts +908 -0
- package/src/modules/face/types.ts +133 -0
- package/src/{id-recognition → modules/id-card}/anti-fake-detector.ts +273 -239
- package/src/modules/id-card/id-card-detector.ts +474 -0
- package/src/modules/id-card/index.ts +425 -0
- package/src/{id-recognition → modules/id-card}/ocr-processor.ts +149 -92
- package/src/modules/id-card/ocr-worker.ts +259 -0
- package/src/modules/id-card/types.ts +178 -0
- package/src/modules/qrcode/index.ts +175 -0
- package/src/modules/qrcode/qr-code-scanner.ts +230 -0
- package/src/modules/qrcode/types.ts +65 -0
- package/src/types/tesseract.d.ts +265 -22
- package/src/utils/image-processing.ts +68 -49
- package/src/utils/index.ts +426 -0
- package/src/utils/performance.ts +168 -131
- package/src/utils/resource-manager.ts +65 -146
- package/src/utils/types.ts +90 -2
- package/src/utils/worker.ts +123 -84
- package/src/version.ts +11 -0
- package/tools/scaffold.js +543 -0
- package/dist/id-scanner-core.esm.js +0 -11349
- package/dist/id-scanner-core.js +0 -11361
- package/dist/id-scanner-core.min.js +0 -1
- package/dist/id-scanner-ocr.esm.js +0 -2319
- package/dist/id-scanner-ocr.js +0 -2328
- package/dist/id-scanner-ocr.min.js +0 -1
- package/dist/id-scanner-qr.esm.js +0 -1296
- package/dist/id-scanner-qr.js +0 -1305
- package/dist/id-scanner-qr.min.js +0 -1
- package/dist/id-scanner.js +0 -4561
- package/dist/id-scanner.min.js +0 -1
- package/src/core.ts +0 -138
- package/src/demo/demo.ts +0 -204
- package/src/id-recognition/data-extractor.ts +0 -262
- package/src/id-recognition/id-detector.ts +0 -510
- package/src/id-recognition/ocr-worker.ts +0 -156
- package/src/index-umd.ts +0 -477
- package/src/ocr-module.ts +0 -187
- package/src/qr-module.ts +0 -179
- package/src/scanner/barcode-scanner.ts +0 -251
- package/src/scanner/qr-scanner.ts +0 -167
package/src/utils/performance.ts
CHANGED
|
@@ -1,210 +1,247 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file
|
|
3
|
-
* @description
|
|
4
|
-
* @module
|
|
2
|
+
* @file 性能优化工具
|
|
3
|
+
* @description 提供性能优化相关的工具函数
|
|
4
|
+
* @module utils/performance
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param fn 需要节流的函数
|
|
11
|
-
* @param delay 延迟时间(毫秒)
|
|
12
|
-
* @returns 节流处理后的函数
|
|
13
|
-
*/
|
|
14
|
-
export function throttle<T extends (...args: any[]) => any>(
|
|
15
|
-
fn: T,
|
|
16
|
-
delay: number
|
|
17
|
-
): (...args: Parameters<T>) => void {
|
|
18
|
-
let lastCall = 0;
|
|
19
|
-
let timeoutId: number | null = null;
|
|
20
|
-
|
|
21
|
-
return function(this: any, ...args: Parameters<T>) {
|
|
22
|
-
const now = Date.now();
|
|
23
|
-
const remaining = delay - (now - lastCall);
|
|
24
|
-
|
|
25
|
-
if (remaining <= 0) {
|
|
26
|
-
if (timeoutId) {
|
|
27
|
-
clearTimeout(timeoutId);
|
|
28
|
-
timeoutId = null;
|
|
29
|
-
}
|
|
30
|
-
lastCall = now;
|
|
31
|
-
fn.apply(this, args);
|
|
32
|
-
} else if (!timeoutId) {
|
|
33
|
-
timeoutId = window.setTimeout(() => {
|
|
34
|
-
lastCall = Date.now();
|
|
35
|
-
timeoutId = null;
|
|
36
|
-
fn.apply(this, args);
|
|
37
|
-
}, remaining);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 防抖函数:函数在最后一次调用后延迟指定时间执行
|
|
44
|
-
*
|
|
45
|
-
* @param fn 需要防抖的函数
|
|
46
|
-
* @param delay 延迟时间(毫秒)
|
|
47
|
-
* @returns 防抖处理后的函数
|
|
48
|
-
*/
|
|
49
|
-
export function debounce<T extends (...args: any[]) => any>(
|
|
50
|
-
fn: T,
|
|
51
|
-
delay: number
|
|
52
|
-
): (...args: Parameters<T>) => void {
|
|
53
|
-
let timeoutId: number | null = null;
|
|
54
|
-
|
|
55
|
-
return function(this: any, ...args: Parameters<T>) {
|
|
56
|
-
if (timeoutId) {
|
|
57
|
-
clearTimeout(timeoutId);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
timeoutId = window.setTimeout(() => {
|
|
61
|
-
fn.apply(this, args);
|
|
62
|
-
timeoutId = null;
|
|
63
|
-
}, delay);
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* LRU缓存类 - 使用最近最少使用策略的缓存实现
|
|
8
|
+
* LRU缓存实现
|
|
69
9
|
*/
|
|
70
10
|
export class LRUCache<K, V> {
|
|
71
|
-
private
|
|
72
|
-
|
|
11
|
+
private capacity: number;
|
|
12
|
+
private cache: Map<K, V>;
|
|
13
|
+
|
|
73
14
|
/**
|
|
74
|
-
*
|
|
75
|
-
* @param
|
|
15
|
+
* 构造函数
|
|
16
|
+
* @param capacity 缓存容量
|
|
76
17
|
*/
|
|
77
|
-
constructor(
|
|
78
|
-
|
|
18
|
+
constructor(capacity: number = 100) {
|
|
19
|
+
this.capacity = capacity;
|
|
20
|
+
this.cache = new Map<K, V>();
|
|
21
|
+
}
|
|
22
|
+
|
|
79
23
|
/**
|
|
80
24
|
* 获取缓存项
|
|
81
|
-
* @param key
|
|
82
|
-
* @returns
|
|
25
|
+
* @param key 键
|
|
26
|
+
* @returns 值,如果不存在则返回undefined
|
|
83
27
|
*/
|
|
84
28
|
get(key: K): V | undefined {
|
|
85
29
|
if (!this.cache.has(key)) {
|
|
86
30
|
return undefined;
|
|
87
31
|
}
|
|
88
|
-
|
|
32
|
+
|
|
89
33
|
// 获取值
|
|
90
34
|
const value = this.cache.get(key)!;
|
|
91
35
|
|
|
92
|
-
//
|
|
36
|
+
// 删除旧位置
|
|
93
37
|
this.cache.delete(key);
|
|
38
|
+
|
|
39
|
+
// 添加到最新位置
|
|
94
40
|
this.cache.set(key, value);
|
|
95
|
-
|
|
41
|
+
|
|
96
42
|
return value;
|
|
97
43
|
}
|
|
98
|
-
|
|
44
|
+
|
|
99
45
|
/**
|
|
100
46
|
* 设置缓存项
|
|
101
|
-
* @param key
|
|
102
|
-
* @param value
|
|
47
|
+
* @param key 键
|
|
48
|
+
* @param value 值
|
|
103
49
|
*/
|
|
104
50
|
set(key: K, value: V): void {
|
|
105
|
-
//
|
|
51
|
+
// 如果已存在,先删除
|
|
106
52
|
if (this.cache.has(key)) {
|
|
107
53
|
this.cache.delete(key);
|
|
108
54
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const oldestKey = this.cache.keys().next().value;
|
|
113
|
-
if (oldestKey !== undefined) {
|
|
114
|
-
this.cache.delete(oldestKey);
|
|
115
|
-
}
|
|
55
|
+
// 如果缓存已满,删除最旧的项
|
|
56
|
+
else if (this.cache.size >= this.capacity) {
|
|
57
|
+
this.cache.delete(this.cache.keys().next().value as K);
|
|
116
58
|
}
|
|
117
|
-
|
|
59
|
+
|
|
118
60
|
// 添加新项
|
|
119
61
|
this.cache.set(key, value);
|
|
120
62
|
}
|
|
121
63
|
|
|
64
|
+
/**
|
|
65
|
+
* 检查键是否存在
|
|
66
|
+
* @param key 键
|
|
67
|
+
* @returns 是否存在
|
|
68
|
+
*/
|
|
69
|
+
has(key: K): boolean {
|
|
70
|
+
return this.cache.has(key);
|
|
71
|
+
}
|
|
72
|
+
|
|
122
73
|
/**
|
|
123
74
|
* 删除缓存项
|
|
124
|
-
* @param key
|
|
75
|
+
* @param key 键
|
|
125
76
|
* @returns 是否成功删除
|
|
126
77
|
*/
|
|
127
78
|
delete(key: K): boolean {
|
|
128
79
|
return this.cache.delete(key);
|
|
129
80
|
}
|
|
130
|
-
|
|
81
|
+
|
|
131
82
|
/**
|
|
132
83
|
* 清空缓存
|
|
133
84
|
*/
|
|
134
85
|
clear(): void {
|
|
135
86
|
this.cache.clear();
|
|
136
87
|
}
|
|
137
|
-
|
|
88
|
+
|
|
138
89
|
/**
|
|
139
|
-
*
|
|
90
|
+
* 获取缓存大小
|
|
140
91
|
*/
|
|
141
92
|
get size(): number {
|
|
142
93
|
return this.cache.size;
|
|
143
94
|
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 获取所有键
|
|
98
|
+
*/
|
|
99
|
+
keys(): IterableIterator<K> {
|
|
100
|
+
return this.cache.keys();
|
|
101
|
+
}
|
|
144
102
|
|
|
145
103
|
/**
|
|
146
|
-
*
|
|
147
|
-
* @param key 缓存键
|
|
104
|
+
* 获取所有值
|
|
148
105
|
*/
|
|
149
|
-
|
|
150
|
-
return this.cache.
|
|
106
|
+
values(): IterableIterator<V> {
|
|
107
|
+
return this.cache.values();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 获取所有项
|
|
112
|
+
*/
|
|
113
|
+
entries(): IterableIterator<[K, V]> {
|
|
114
|
+
return this.cache.entries();
|
|
151
115
|
}
|
|
152
116
|
}
|
|
153
117
|
|
|
154
118
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
119
|
+
* 计算图像指纹
|
|
157
120
|
* @param imageData 图像数据
|
|
158
|
-
* @
|
|
159
|
-
* @returns 图像指纹字符串
|
|
121
|
+
* @returns 图像指纹
|
|
160
122
|
*/
|
|
161
|
-
export function calculateImageFingerprint(imageData: ImageData
|
|
162
|
-
|
|
123
|
+
export function calculateImageFingerprint(imageData: ImageData): string {
|
|
124
|
+
const { width, height, data } = imageData;
|
|
125
|
+
|
|
126
|
+
// 缩小图像以加快计算速度
|
|
127
|
+
const scale = Math.min(1, 32 / Math.max(width, height));
|
|
128
|
+
const scaledWidth = Math.max(8, Math.floor(width * scale));
|
|
129
|
+
const scaledHeight = Math.max(8, Math.floor(height * scale));
|
|
130
|
+
|
|
131
|
+
// 创建缩小的图像
|
|
163
132
|
const canvas = document.createElement('canvas');
|
|
164
|
-
canvas.width = size;
|
|
165
|
-
canvas.height = size;
|
|
166
133
|
const ctx = canvas.getContext('2d');
|
|
167
|
-
|
|
134
|
+
|
|
168
135
|
if (!ctx) {
|
|
169
|
-
|
|
136
|
+
throw new Error('无法创建Canvas上下文');
|
|
170
137
|
}
|
|
171
138
|
|
|
172
|
-
//
|
|
139
|
+
// 设置canvas尺寸
|
|
140
|
+
canvas.width = scaledWidth;
|
|
141
|
+
canvas.height = scaledHeight;
|
|
142
|
+
|
|
143
|
+
// 创建临时canvas存储原始ImageData
|
|
173
144
|
const tempCanvas = document.createElement('canvas');
|
|
174
|
-
tempCanvas.width = imageData.width;
|
|
175
|
-
tempCanvas.height = imageData.height;
|
|
176
145
|
const tempCtx = tempCanvas.getContext('2d');
|
|
177
|
-
|
|
146
|
+
|
|
178
147
|
if (!tempCtx) {
|
|
179
|
-
|
|
148
|
+
throw new Error('无法创建临时Canvas上下文');
|
|
180
149
|
}
|
|
181
|
-
|
|
150
|
+
|
|
151
|
+
tempCanvas.width = width;
|
|
152
|
+
tempCanvas.height = height;
|
|
182
153
|
tempCtx.putImageData(imageData, 0, 0);
|
|
183
154
|
|
|
184
|
-
//
|
|
185
|
-
ctx.drawImage(tempCanvas, 0, 0,
|
|
155
|
+
// 绘制缩小的图像
|
|
156
|
+
ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, scaledWidth, scaledHeight);
|
|
186
157
|
|
|
187
|
-
//
|
|
188
|
-
const
|
|
189
|
-
const grayValues = [];
|
|
158
|
+
// 获取缩小的图像数据
|
|
159
|
+
const scaledImageData = ctx.getImageData(0, 0, scaledWidth, scaledHeight);
|
|
190
160
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
161
|
+
// 计算灰度值
|
|
162
|
+
const grayValues = new Uint8Array(scaledWidth * scaledHeight);
|
|
163
|
+
|
|
164
|
+
for (let i = 0; i < scaledWidth * scaledHeight; i++) {
|
|
165
|
+
const idx = i * 4;
|
|
166
|
+
grayValues[i] = Math.round(
|
|
167
|
+
0.299 * scaledImageData.data[idx] +
|
|
168
|
+
0.587 * scaledImageData.data[idx + 1] +
|
|
169
|
+
0.114 * scaledImageData.data[idx + 2]
|
|
170
|
+
);
|
|
198
171
|
}
|
|
199
172
|
|
|
200
|
-
//
|
|
201
|
-
|
|
173
|
+
// 计算平均值
|
|
174
|
+
let sum = 0;
|
|
175
|
+
for (let i = 0; i < grayValues.length; i++) {
|
|
176
|
+
sum += grayValues[i];
|
|
177
|
+
}
|
|
178
|
+
const avg = sum / grayValues.length;
|
|
202
179
|
|
|
203
|
-
//
|
|
204
|
-
let
|
|
205
|
-
for (
|
|
206
|
-
|
|
180
|
+
// 计算哈希值
|
|
181
|
+
let hash = '';
|
|
182
|
+
for (let i = 0; i < grayValues.length; i++) {
|
|
183
|
+
hash += grayValues[i] >= avg ? '1' : '0';
|
|
207
184
|
}
|
|
208
185
|
|
|
209
|
-
return
|
|
210
|
-
}
|
|
186
|
+
return hash;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 防抖函数
|
|
191
|
+
* @param func 要执行的函数
|
|
192
|
+
* @param wait 等待时间(毫秒)
|
|
193
|
+
* @returns 防抖处理后的函数
|
|
194
|
+
*/
|
|
195
|
+
export function debounce<T extends (...args: any[]) => any>(
|
|
196
|
+
func: T,
|
|
197
|
+
wait: number
|
|
198
|
+
): (...args: Parameters<T>) => void {
|
|
199
|
+
let timeout: number | null = null;
|
|
200
|
+
|
|
201
|
+
return function(this: any, ...args: Parameters<T>): void {
|
|
202
|
+
const later = () => {
|
|
203
|
+
timeout = null;
|
|
204
|
+
func.apply(this, args);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
if (timeout !== null) {
|
|
208
|
+
clearTimeout(timeout);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
timeout = window.setTimeout(later, wait) as unknown as number;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* 节流函数
|
|
217
|
+
* @param func 要执行的函数
|
|
218
|
+
* @param limit 时间限制(毫秒)
|
|
219
|
+
* @returns 节流处理后的函数
|
|
220
|
+
*/
|
|
221
|
+
export function throttle<T extends (...args: any[]) => any>(
|
|
222
|
+
func: T,
|
|
223
|
+
limit: number
|
|
224
|
+
): (...args: Parameters<T>) => void {
|
|
225
|
+
let inThrottle = false;
|
|
226
|
+
let lastFunc: number | null = null;
|
|
227
|
+
let lastRan: number | null = null;
|
|
228
|
+
|
|
229
|
+
return function(this: any, ...args: Parameters<T>): void {
|
|
230
|
+
if (!inThrottle) {
|
|
231
|
+
func.apply(this, args);
|
|
232
|
+
lastRan = Date.now();
|
|
233
|
+
inThrottle = true;
|
|
234
|
+
} else {
|
|
235
|
+
if (lastFunc !== null) {
|
|
236
|
+
clearTimeout(lastFunc);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
lastFunc = window.setTimeout(() => {
|
|
240
|
+
if (lastRan !== null && Date.now() - lastRan >= limit) {
|
|
241
|
+
func.apply(this, args);
|
|
242
|
+
lastRan = Date.now();
|
|
243
|
+
}
|
|
244
|
+
}, limit - (lastRan !== null ? Date.now() - lastRan : 0)) as unknown as number;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -1,198 +1,117 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file 资源管理器
|
|
3
|
-
* @description
|
|
4
|
-
* @module
|
|
3
|
+
* @description 提供资源管理和释放功能
|
|
4
|
+
* @module utils/resource-manager
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 可释放资源接口
|
|
9
9
|
*/
|
|
10
10
|
export interface Disposable {
|
|
11
|
-
|
|
11
|
+
/** 释放资源 */
|
|
12
|
+
dispose(): Promise<void> | void;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 用于管理和自动释放资源,防止内存泄漏
|
|
16
|
+
* 资源管理器类
|
|
17
|
+
* 用于管理和自动释放资源
|
|
18
18
|
*/
|
|
19
19
|
export class ResourceManager {
|
|
20
|
-
private resources:
|
|
21
|
-
private disposeTimeouts: Map<string, number> = new Map();
|
|
22
|
-
private autoDisposeDelay: number;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 创建资源管理器
|
|
26
|
-
* @param autoDisposeDelay 自动释放延迟时间(毫秒),默认5分钟
|
|
27
|
-
*/
|
|
28
|
-
constructor(autoDisposeDelay: number = 5 * 60 * 1000) {
|
|
29
|
-
this.autoDisposeDelay = autoDisposeDelay;
|
|
30
|
-
|
|
31
|
-
// 添加页面卸载事件监听,确保在页面关闭时释放所有资源
|
|
32
|
-
if (typeof window !== 'undefined') {
|
|
33
|
-
window.addEventListener('beforeunload', () => {
|
|
34
|
-
this.disposeAll();
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
20
|
+
private resources: Disposable[] = [];
|
|
38
21
|
|
|
39
22
|
/**
|
|
40
23
|
* 注册资源
|
|
41
|
-
*
|
|
42
|
-
* @param id 资源标识符
|
|
43
24
|
* @param resource 可释放资源
|
|
44
|
-
* @
|
|
45
|
-
* @returns 注册的资源
|
|
46
|
-
*/
|
|
47
|
-
register<T extends Disposable>(id: string, resource: T, autoDispose: boolean = true): T {
|
|
48
|
-
// 如果已存在同ID资源,先释放它
|
|
49
|
-
if (this.resources.has(id)) {
|
|
50
|
-
this.dispose(id);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
this.resources.set(id, resource);
|
|
54
|
-
|
|
55
|
-
// 如果启用自动释放,设置定时器
|
|
56
|
-
if (autoDispose) {
|
|
57
|
-
this.resetDisposeTimeout(id);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return resource;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 重置资源自动释放定时器
|
|
65
|
-
*
|
|
66
|
-
* @param id 资源标识符
|
|
67
|
-
*/
|
|
68
|
-
resetDisposeTimeout(id: string): void {
|
|
69
|
-
// 取消现有定时器
|
|
70
|
-
if (this.disposeTimeouts.has(id)) {
|
|
71
|
-
window.clearTimeout(this.disposeTimeouts.get(id)!);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// 设置新定时器
|
|
75
|
-
const timeoutId = window.setTimeout(() => {
|
|
76
|
-
this.dispose(id);
|
|
77
|
-
}, this.autoDisposeDelay);
|
|
78
|
-
|
|
79
|
-
this.disposeTimeouts.set(id, timeoutId);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 获取资源
|
|
84
|
-
*
|
|
85
|
-
* @param id 资源标识符
|
|
86
|
-
* @returns 资源对象或undefined
|
|
25
|
+
* @returns 资源本身,便于链式调用
|
|
87
26
|
*/
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// 重置自动释放定时器(仅当资源存在且有定时器时)
|
|
92
|
-
if (resource && this.disposeTimeouts.has(id)) {
|
|
93
|
-
this.resetDisposeTimeout(id);
|
|
94
|
-
}
|
|
95
|
-
|
|
27
|
+
register<T extends Disposable>(resource: T): T {
|
|
28
|
+
this.resources.push(resource);
|
|
96
29
|
return resource;
|
|
97
30
|
}
|
|
98
31
|
|
|
99
32
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* @param id 资源标识符
|
|
33
|
+
* 释放指定资源
|
|
34
|
+
* @param resource 要释放的资源
|
|
103
35
|
* @returns 是否成功释放
|
|
104
36
|
*/
|
|
105
|
-
async
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (this.disposeTimeouts.has(id)) {
|
|
112
|
-
window.clearTimeout(this.disposeTimeouts.get(id)!);
|
|
113
|
-
this.disposeTimeouts.delete(id);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 释放资源
|
|
117
|
-
try {
|
|
118
|
-
const resource = this.resources.get(id)!;
|
|
119
|
-
const result = resource.dispose();
|
|
120
|
-
|
|
121
|
-
// 处理可能的Promise结果
|
|
122
|
-
if (result instanceof Promise) {
|
|
123
|
-
await result;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
this.resources.delete(id);
|
|
37
|
+
async release(resource: Disposable): Promise<boolean> {
|
|
38
|
+
const index = this.resources.indexOf(resource);
|
|
39
|
+
if (index !== -1) {
|
|
40
|
+
try {
|
|
41
|
+
await resource.dispose();
|
|
42
|
+
this.resources.splice(index, 1);
|
|
127
43
|
return true;
|
|
128
44
|
} catch (error) {
|
|
129
|
-
|
|
130
|
-
// 尽管出错,仍然从管理器中移除
|
|
131
|
-
this.resources.delete(id);
|
|
45
|
+
console.error('释放资源失败:', error);
|
|
132
46
|
return false;
|
|
47
|
+
}
|
|
133
48
|
}
|
|
49
|
+
return false;
|
|
134
50
|
}
|
|
135
51
|
|
|
136
52
|
/**
|
|
137
53
|
* 释放所有资源
|
|
138
54
|
*/
|
|
139
|
-
async
|
|
140
|
-
|
|
141
|
-
for (const timeoutId of this.disposeTimeouts.values()) {
|
|
142
|
-
window.clearTimeout(timeoutId);
|
|
143
|
-
}
|
|
144
|
-
this.disposeTimeouts.clear();
|
|
145
|
-
|
|
146
|
-
// 并行释放所有资源
|
|
147
|
-
const disposePromises = [];
|
|
55
|
+
async releaseAll(): Promise<void> {
|
|
56
|
+
const promises: Promise<void>[] = [];
|
|
148
57
|
|
|
149
|
-
for (const
|
|
58
|
+
for (const resource of this.resources) {
|
|
150
59
|
try {
|
|
151
60
|
const result = resource.dispose();
|
|
152
61
|
if (result instanceof Promise) {
|
|
153
|
-
|
|
62
|
+
promises.push(result);
|
|
154
63
|
}
|
|
155
64
|
} catch (error) {
|
|
156
|
-
console.error(
|
|
65
|
+
console.error('释放资源失败:', error);
|
|
157
66
|
}
|
|
158
67
|
}
|
|
159
68
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await Promise.all(disposePromises);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
this.resources.clear();
|
|
69
|
+
await Promise.all(promises);
|
|
70
|
+
this.resources = [];
|
|
166
71
|
}
|
|
167
72
|
|
|
168
73
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* @param maxAge 资源最大年龄(毫秒)
|
|
74
|
+
* 获取当前管理的资源数量
|
|
172
75
|
*/
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
for (const [id, timeoutId] of this.disposeTimeouts.entries()) {
|
|
177
|
-
// 计算资源年龄:自动释放延迟时间 - 剩余时间
|
|
178
|
-
const remainingTime = this.getRemainingTime(timeoutId);
|
|
179
|
-
const age = this.autoDisposeDelay - remainingTime;
|
|
180
|
-
|
|
181
|
-
if (age > maxAge) {
|
|
182
|
-
this.dispose(id);
|
|
183
|
-
}
|
|
76
|
+
get count(): number {
|
|
77
|
+
return this.resources.length;
|
|
184
78
|
}
|
|
185
79
|
}
|
|
186
80
|
|
|
187
81
|
/**
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
82
|
+
* 创建一个自动释放的资源
|
|
83
|
+
* @param factory 资源工厂函数
|
|
84
|
+
* @param disposeCallback 释放回调函数
|
|
85
|
+
* @returns 创建的资源
|
|
86
|
+
*/
|
|
87
|
+
export function createDisposable<T>(
|
|
88
|
+
factory: () => T,
|
|
89
|
+
disposeCallback: (resource: T) => Promise<void> | void
|
|
90
|
+
): T & Disposable {
|
|
91
|
+
const resource = factory();
|
|
92
|
+
|
|
93
|
+
// 添加dispose方法
|
|
94
|
+
(resource as any).dispose = async () => {
|
|
95
|
+
await disposeCallback(resource);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return resource as T & Disposable;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 使用资源并自动释放
|
|
103
|
+
* @param resource 可释放资源
|
|
104
|
+
* @param callback 使用资源的回调函数
|
|
105
|
+
* @returns 回调函数的返回值
|
|
106
|
+
*/
|
|
107
|
+
export async function using<T extends Disposable, R>(
|
|
108
|
+
resource: T,
|
|
109
|
+
callback: (resource: T) => Promise<R> | R
|
|
110
|
+
): Promise<R> {
|
|
111
|
+
try {
|
|
112
|
+
const result = await callback(resource);
|
|
113
|
+
return result;
|
|
114
|
+
} finally {
|
|
115
|
+
await resource.dispose();
|
|
197
116
|
}
|
|
198
117
|
}
|