koatty_validation 1.3.6 → 1.4.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/.rollup.config.js +62 -59
- package/.vscode/launch.json +81 -0
- package/CHANGELOG.md +83 -75
- package/LICENSE +29 -29
- package/README.md +363 -116
- package/coverage.lcov +1607 -0
- package/dist/LICENSE +29 -29
- package/dist/README.md +363 -116
- package/dist/index.d.ts +421 -219
- package/dist/index.js +799 -2074
- package/dist/index.mjs +768 -2059
- package/dist/package.json +91 -94
- package/examples/README.md +90 -0
- package/examples/basic-usage.ts +239 -0
- package/examples/custom-decorators-example.ts +230 -0
- package/examples/usage-example.ts +284 -0
- package/package.json +91 -94
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自定义装饰器示例
|
|
3
|
+
* 演示如何使用装饰器工厂创建各种自定义验证装饰器
|
|
4
|
+
* @author richen
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as helper from "koatty_lib";
|
|
8
|
+
import { ValidationOptions } from "class-validator";
|
|
9
|
+
import {
|
|
10
|
+
createSimpleDecorator,
|
|
11
|
+
createParameterizedDecorator,
|
|
12
|
+
createValidationDecorator
|
|
13
|
+
} from "../src/decorator-factory";
|
|
14
|
+
|
|
15
|
+
// ==================== 简单验证装饰器示例 ====================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 检查是否为正整数
|
|
19
|
+
*/
|
|
20
|
+
export const IsPositiveInteger = createSimpleDecorator(
|
|
21
|
+
'IsPositiveInteger',
|
|
22
|
+
(value: any) => {
|
|
23
|
+
const num = helper.toNumber(value);
|
|
24
|
+
return Number.isInteger(num) && num > 0;
|
|
25
|
+
},
|
|
26
|
+
'must be a positive integer'
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 检查是否为有效的颜色代码(十六进制)
|
|
31
|
+
*/
|
|
32
|
+
export const IsHexColor = createSimpleDecorator(
|
|
33
|
+
'IsHexColor',
|
|
34
|
+
(value: any) => {
|
|
35
|
+
if (!helper.isString(value)) return false;
|
|
36
|
+
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value);
|
|
37
|
+
},
|
|
38
|
+
'must be a valid hex color code (e.g., #FF0000 or #F00)'
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 检查是否为有效的JSON字符串
|
|
43
|
+
*/
|
|
44
|
+
export const IsJsonString = createSimpleDecorator(
|
|
45
|
+
'IsJsonString',
|
|
46
|
+
(value: any) => {
|
|
47
|
+
if (!helper.isString(value)) return false;
|
|
48
|
+
try {
|
|
49
|
+
JSON.parse(value);
|
|
50
|
+
return true;
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
'must be a valid JSON string'
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// ==================== 带参数的验证装饰器示例 ====================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 检查字符串是否包含指定的所有子字符串
|
|
62
|
+
*/
|
|
63
|
+
export const ContainsAll = createParameterizedDecorator(
|
|
64
|
+
'ContainsAll',
|
|
65
|
+
(value: any, requiredSubstrings: string[]) => {
|
|
66
|
+
if (!helper.isString(value)) return false;
|
|
67
|
+
return requiredSubstrings.every(substring => value.includes(substring));
|
|
68
|
+
},
|
|
69
|
+
'must contain all required substrings: $constraint1'
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 检查数组长度是否在指定范围内
|
|
74
|
+
*/
|
|
75
|
+
export const ArrayLength = createParameterizedDecorator(
|
|
76
|
+
'ArrayLength',
|
|
77
|
+
(value: any, min: number, max?: number) => {
|
|
78
|
+
if (!Array.isArray(value)) return false;
|
|
79
|
+
if (max !== undefined) {
|
|
80
|
+
return value.length >= min && value.length <= max;
|
|
81
|
+
}
|
|
82
|
+
return value.length >= min;
|
|
83
|
+
},
|
|
84
|
+
'array length must be within the specified range'
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 检查数值是否在指定范围内(包含边界)
|
|
89
|
+
*/
|
|
90
|
+
export const InRange = createParameterizedDecorator(
|
|
91
|
+
'InRange',
|
|
92
|
+
(value: any, min: number, max: number) => {
|
|
93
|
+
const num = helper.toNumber(value);
|
|
94
|
+
return num >= min && num <= max;
|
|
95
|
+
},
|
|
96
|
+
'must be between $constraint1 and $constraint2 (inclusive)'
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// ==================== 复杂自定义装饰器示例 ====================
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 检查密码强度
|
|
103
|
+
* 要求:至少8位,包含大小写字母、数字和特殊字符
|
|
104
|
+
*/
|
|
105
|
+
export const IsStrongPassword = createSimpleDecorator(
|
|
106
|
+
'IsStrongPassword',
|
|
107
|
+
(value: any) => {
|
|
108
|
+
if (!helper.isString(value)) return false;
|
|
109
|
+
|
|
110
|
+
const hasLowercase = /[a-z]/.test(value);
|
|
111
|
+
const hasUppercase = /[A-Z]/.test(value);
|
|
112
|
+
const hasNumbers = /\d/.test(value);
|
|
113
|
+
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value);
|
|
114
|
+
const isLongEnough = value.length >= 8;
|
|
115
|
+
|
|
116
|
+
return hasLowercase && hasUppercase && hasNumbers && hasSpecialChar && isLongEnough;
|
|
117
|
+
},
|
|
118
|
+
'password must be at least 8 characters long and contain uppercase, lowercase, number and special character'
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 检查业务时间(工作日的9:00-18:00)
|
|
123
|
+
*/
|
|
124
|
+
export const IsBusinessHours = createSimpleDecorator(
|
|
125
|
+
'IsBusinessHours',
|
|
126
|
+
(value: any) => {
|
|
127
|
+
const date = new Date(value);
|
|
128
|
+
if (isNaN(date.getTime())) return false;
|
|
129
|
+
|
|
130
|
+
const dayOfWeek = date.getDay(); // 0 = Sunday, 6 = Saturday
|
|
131
|
+
const hour = date.getHours();
|
|
132
|
+
|
|
133
|
+
// 工作日(周一到周五)的9:00-18:00
|
|
134
|
+
return dayOfWeek >= 1 && dayOfWeek <= 5 && hour >= 9 && hour < 18;
|
|
135
|
+
},
|
|
136
|
+
'must be during business hours (Mon-Fri 9:00-18:00)'
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// ==================== 使用装饰器工厂的高级示例 ====================
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 动态文件扩展名验证器
|
|
143
|
+
*/
|
|
144
|
+
export function IsFileExtension(allowedExtensions: string[], validationOptions?: ValidationOptions) {
|
|
145
|
+
return createValidationDecorator({
|
|
146
|
+
name: 'IsFileExtension',
|
|
147
|
+
validator: (value: any) => {
|
|
148
|
+
if (!helper.isString(value)) return false;
|
|
149
|
+
const extension = value.toLowerCase().split('.').pop();
|
|
150
|
+
return extension ? allowedExtensions.includes(extension) : false;
|
|
151
|
+
},
|
|
152
|
+
defaultMessage: `file must have one of the following extensions: ${allowedExtensions.join(', ')}`,
|
|
153
|
+
requiresValue: false
|
|
154
|
+
})(validationOptions);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 自定义正则表达式验证器
|
|
159
|
+
*/
|
|
160
|
+
export function MatchesPattern(pattern: RegExp, validationOptions?: ValidationOptions) {
|
|
161
|
+
return createValidationDecorator({
|
|
162
|
+
name: 'MatchesPattern',
|
|
163
|
+
validator: (value: any) => {
|
|
164
|
+
if (!helper.isString(value)) return false;
|
|
165
|
+
return pattern.test(value);
|
|
166
|
+
},
|
|
167
|
+
defaultMessage: `must match the pattern ${pattern.toString()}`,
|
|
168
|
+
requiresValue: false
|
|
169
|
+
})(validationOptions);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 异步验证器示例(注意:这只是概念示例,实际使用需要配合异步验证机制)
|
|
174
|
+
*/
|
|
175
|
+
export function IsUniqueEmail(validationOptions?: ValidationOptions) {
|
|
176
|
+
return createValidationDecorator({
|
|
177
|
+
name: 'IsUniqueEmail',
|
|
178
|
+
validator: (value: any) => {
|
|
179
|
+
// 在实际应用中,这里应该是异步的数据库查询
|
|
180
|
+
// 这里只是一个同步的演示
|
|
181
|
+
if (!helper.isString(value)) return false;
|
|
182
|
+
|
|
183
|
+
// 模拟检查邮箱是否已存在
|
|
184
|
+
const existingEmails = ['admin@example.com', 'test@example.com'];
|
|
185
|
+
return !existingEmails.includes(value.toLowerCase());
|
|
186
|
+
},
|
|
187
|
+
defaultMessage: 'email address is already in use',
|
|
188
|
+
requiresValue: false
|
|
189
|
+
})(validationOptions);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ==================== 使用示例 ====================
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 用户注册数据传输对象示例
|
|
196
|
+
*/
|
|
197
|
+
export class UserRegistrationDto {
|
|
198
|
+
@IsStrongPassword()
|
|
199
|
+
password: string;
|
|
200
|
+
|
|
201
|
+
@IsUniqueEmail()
|
|
202
|
+
email: string;
|
|
203
|
+
|
|
204
|
+
@IsHexColor()
|
|
205
|
+
favoriteColor: string;
|
|
206
|
+
|
|
207
|
+
@IsPositiveInteger()
|
|
208
|
+
age: number;
|
|
209
|
+
|
|
210
|
+
@ContainsAll(['profile'])
|
|
211
|
+
jsonData: string;
|
|
212
|
+
|
|
213
|
+
@ArrayLength(1, 5)
|
|
214
|
+
hobbies: string[];
|
|
215
|
+
|
|
216
|
+
@InRange(18, 120)
|
|
217
|
+
realAge: number;
|
|
218
|
+
|
|
219
|
+
@IsFileExtension(['jpg', 'png', 'gif'])
|
|
220
|
+
avatar: string;
|
|
221
|
+
|
|
222
|
+
@MatchesPattern(/^[A-Z][a-z]+$/)
|
|
223
|
+
firstName: string;
|
|
224
|
+
|
|
225
|
+
@IsBusinessHours()
|
|
226
|
+
interviewTime: Date;
|
|
227
|
+
|
|
228
|
+
@IsJsonString()
|
|
229
|
+
metadata: string;
|
|
230
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 使用示例 - 展示优化后的验证模块功能
|
|
3
|
+
* @author richen
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// 1. 使用重构后的装饰器
|
|
7
|
+
import {
|
|
8
|
+
IsCnName, IsIdNumber, IsMobile, IsNotEmpty,
|
|
9
|
+
Gt, Contains, IsEmail
|
|
10
|
+
} from '../src/decorators';
|
|
11
|
+
|
|
12
|
+
// 2. 使用错误处理机制
|
|
13
|
+
import {
|
|
14
|
+
setValidationLanguage,
|
|
15
|
+
KoattyValidationError,
|
|
16
|
+
createValidationErrors
|
|
17
|
+
} from '../src/error-handler';
|
|
18
|
+
|
|
19
|
+
// 3. 使用性能缓存
|
|
20
|
+
import {
|
|
21
|
+
getAllCacheStats,
|
|
22
|
+
warmupCaches,
|
|
23
|
+
configureCaches,
|
|
24
|
+
performanceMonitor
|
|
25
|
+
} from '../src/performance-cache';
|
|
26
|
+
|
|
27
|
+
// 4. 使用原有的验证功能
|
|
28
|
+
import { ClassValidator } from '../src/rule';
|
|
29
|
+
import { Valid, Validated } from '../src/decorators';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 用户DTO示例 - 使用重构后的装饰器
|
|
33
|
+
*/
|
|
34
|
+
export class UserDTO {
|
|
35
|
+
@IsNotEmpty({ message: "用户名不能为空" })
|
|
36
|
+
@IsCnName({ message: "必须是有效的中文姓名" })
|
|
37
|
+
name: string;
|
|
38
|
+
|
|
39
|
+
@IsIdNumber({ message: "身份证号码格式不正确" })
|
|
40
|
+
idNumber: string = "110101199001011237";
|
|
41
|
+
|
|
42
|
+
@IsMobile({ message: "手机号格式不正确" })
|
|
43
|
+
phone: string;
|
|
44
|
+
|
|
45
|
+
@IsEmail({}, { message: "邮箱格式不正确" })
|
|
46
|
+
email: string;
|
|
47
|
+
|
|
48
|
+
@Gt(0, { message: "年龄必须大于0" })
|
|
49
|
+
age: number;
|
|
50
|
+
|
|
51
|
+
@Contains("@", { message: "用户名必须包含@符号" })
|
|
52
|
+
username: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 控制器示例
|
|
57
|
+
*/
|
|
58
|
+
export class UserController {
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 使用@Valid装饰器进行参数验证
|
|
62
|
+
*/
|
|
63
|
+
getUserById(
|
|
64
|
+
@Valid("IsNotEmpty", "用户ID不能为空") id: string,
|
|
65
|
+
@Valid(["IsNotEmpty", "IsEmail"], "邮箱格式不正确") email: string
|
|
66
|
+
) {
|
|
67
|
+
return { id, email };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 使用@Validated装饰器进行DTO验证
|
|
72
|
+
*/
|
|
73
|
+
@Validated()
|
|
74
|
+
createUser(userData: UserDTO) {
|
|
75
|
+
return { success: true, data: userData };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 错误处理示例
|
|
81
|
+
*/
|
|
82
|
+
export class ValidationExample {
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 设置验证语言
|
|
86
|
+
*/
|
|
87
|
+
static setupLanguage() {
|
|
88
|
+
// 设置为中文
|
|
89
|
+
setValidationLanguage('zh');
|
|
90
|
+
|
|
91
|
+
// 或设置为英文
|
|
92
|
+
// setValidationLanguage('en');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 手动创建验证错误
|
|
97
|
+
*/
|
|
98
|
+
static createCustomErrors() {
|
|
99
|
+
const errors = createValidationErrors([
|
|
100
|
+
{
|
|
101
|
+
field: 'name',
|
|
102
|
+
value: '',
|
|
103
|
+
constraint: 'IsNotEmpty',
|
|
104
|
+
message: '姓名不能为空'
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
field: 'age',
|
|
108
|
+
value: -1,
|
|
109
|
+
constraint: 'Gt',
|
|
110
|
+
message: '年龄必须大于0',
|
|
111
|
+
context: { min: 0 }
|
|
112
|
+
}
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
console.log('验证错误:', errors.toJSON());
|
|
116
|
+
return errors;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 处理验证错误
|
|
121
|
+
*/
|
|
122
|
+
static async handleValidation() {
|
|
123
|
+
try {
|
|
124
|
+
const invalidUser = {
|
|
125
|
+
name: '',
|
|
126
|
+
idNumber: '123',
|
|
127
|
+
phone: '456',
|
|
128
|
+
email: 'invalid-email',
|
|
129
|
+
age: -1,
|
|
130
|
+
username: 'noatsymbol'
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
await ClassValidator.valid(UserDTO, invalidUser, true);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error instanceof KoattyValidationError) {
|
|
136
|
+
console.log('验证失败:', error.getFirstError());
|
|
137
|
+
console.log('所有错误:', error.errors);
|
|
138
|
+
} else {
|
|
139
|
+
console.log('其他错误:', error.message);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 性能优化示例
|
|
147
|
+
*/
|
|
148
|
+
export class PerformanceExample {
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 初始化性能优化
|
|
152
|
+
*/
|
|
153
|
+
static setup() {
|
|
154
|
+
// 1. 预热缓存
|
|
155
|
+
warmupCaches();
|
|
156
|
+
|
|
157
|
+
// 2. 配置缓存设置
|
|
158
|
+
configureCaches({
|
|
159
|
+
validation: {
|
|
160
|
+
max: 10000, // 最大缓存条目数
|
|
161
|
+
ttl: 1000 * 60 * 15, // 15分钟过期时间
|
|
162
|
+
allowStale: false,
|
|
163
|
+
updateAgeOnGet: true
|
|
164
|
+
},
|
|
165
|
+
regex: {
|
|
166
|
+
max: 500,
|
|
167
|
+
ttl: 1000 * 60 * 30, // 30分钟过期时间
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 性能监控示例
|
|
174
|
+
*/
|
|
175
|
+
static async performanceMonitoring() {
|
|
176
|
+
console.log('=== 性能监控示例 ===');
|
|
177
|
+
|
|
178
|
+
// 执行一些验证操作
|
|
179
|
+
const testData = [
|
|
180
|
+
{ name: '张三', phone: '13812345678' },
|
|
181
|
+
{ name: '李四', phone: '13987654321' },
|
|
182
|
+
{ name: '王五', phone: '15612345678' },
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
for (const data of testData) {
|
|
186
|
+
const timer = performanceMonitor.startTimer('user-validation');
|
|
187
|
+
try {
|
|
188
|
+
await ClassValidator.valid(UserDTO, data, true);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
// 忽略验证错误,我们只关心性能
|
|
191
|
+
} finally {
|
|
192
|
+
timer();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 获取性能报告
|
|
197
|
+
const stats = getAllCacheStats();
|
|
198
|
+
console.log('缓存统计:', stats);
|
|
199
|
+
|
|
200
|
+
// 获取性能热点
|
|
201
|
+
const hotspots = performanceMonitor.getHotspots(5);
|
|
202
|
+
console.log('性能热点:', hotspots);
|
|
203
|
+
|
|
204
|
+
// 导出性能数据
|
|
205
|
+
const csvData = performanceMonitor.exportToCSV();
|
|
206
|
+
console.log('性能数据CSV:', csvData);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 缓存效果演示
|
|
211
|
+
*/
|
|
212
|
+
static demonstrateCaching() {
|
|
213
|
+
console.log('=== 缓存效果演示 ===');
|
|
214
|
+
|
|
215
|
+
const testValue = '张三';
|
|
216
|
+
|
|
217
|
+
// 第一次调用(无缓存)
|
|
218
|
+
console.time('第一次验证');
|
|
219
|
+
const result1 = ClassValidator.valid(UserDTO, { name: testValue });
|
|
220
|
+
console.timeEnd('第一次验证');
|
|
221
|
+
|
|
222
|
+
// 第二次调用(有缓存)
|
|
223
|
+
console.time('第二次验证');
|
|
224
|
+
const result2 = ClassValidator.valid(UserDTO, { name: testValue });
|
|
225
|
+
console.timeEnd('第二次验证');
|
|
226
|
+
|
|
227
|
+
console.log('缓存统计:', getAllCacheStats());
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* 完整使用示例
|
|
233
|
+
*/
|
|
234
|
+
export async function completeExample() {
|
|
235
|
+
console.log('=== Koatty Validation 完整示例 ===');
|
|
236
|
+
|
|
237
|
+
// 1. 设置语言和性能优化
|
|
238
|
+
ValidationExample.setupLanguage();
|
|
239
|
+
PerformanceExample.setup();
|
|
240
|
+
|
|
241
|
+
// 2. 创建用户控制器
|
|
242
|
+
const userController = new UserController();
|
|
243
|
+
|
|
244
|
+
// 3. 测试参数验证
|
|
245
|
+
try {
|
|
246
|
+
const result = userController.getUserById('123', 'test@example.com');
|
|
247
|
+
console.log('参数验证成功:', result);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.log('参数验证失败:', error.message);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 4. 测试DTO验证
|
|
253
|
+
try {
|
|
254
|
+
const userData = {
|
|
255
|
+
name: '张三',
|
|
256
|
+
idNumber: '110101199001011234',
|
|
257
|
+
phone: '13812345678',
|
|
258
|
+
email: 'zhangsan@example.com',
|
|
259
|
+
age: 25,
|
|
260
|
+
username: 'zhangsan@123'
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const result = userController.createUser(userData);
|
|
264
|
+
console.log('DTO验证成功:', result);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.log('DTO验证失败:', error.message);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// 5. 错误处理示例
|
|
270
|
+
await ValidationExample.handleValidation();
|
|
271
|
+
|
|
272
|
+
// 6. 性能监控
|
|
273
|
+
await PerformanceExample.performanceMonitoring();
|
|
274
|
+
|
|
275
|
+
// 7. 缓存效果演示
|
|
276
|
+
PerformanceExample.demonstrateCaching();
|
|
277
|
+
|
|
278
|
+
console.log('=== 示例完成 ===');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 如果直接运行此文件,执行完整示例
|
|
282
|
+
if (require.main === module) {
|
|
283
|
+
completeExample().catch(console.error);
|
|
284
|
+
}
|