面试题答案
一键面试1. 基于TypeScript装饰器实现面向切面编程
权限验证装饰器
// 权限验证装饰器
function checkPermissions(requiredPermissions: string[]) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 模拟获取当前用户权限
const userPermissions = ['read', 'write'];
const hasPermission = requiredPermissions.some(permission => userPermissions.includes(permission));
if (!hasPermission) {
throw new Error('没有足够权限');
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
class UserService {
@checkPermissions(['read'])
getUser() {
return '获取用户信息';
}
}
日志记录装饰器
// 日志记录装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`调用方法 ${propertyKey},参数:`, args);
const result = originalMethod.apply(this, args);
console.log(`方法 ${propertyKey} 返回结果:`, result);
return result;
};
return descriptor;
}
class ProductService {
@log
getProduct() {
return '获取产品信息';
}
}
性能监控装饰器
// 性能监控装饰器
function performanceMonitor(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const start = Date.now();
const result = originalMethod.apply(this, args);
const end = Date.now();
console.log(`方法 ${propertyKey} 执行时间: ${end - start} ms`);
return result;
};
return descriptor;
}
class OrderService {
@performanceMonitor
placeOrder() {
// 模拟业务逻辑
for (let i = 0; i < 1000000; i++);
return '订单已提交';
}
}
2. 装饰器性能优化
- 缓存计算结果:对于一些计算成本较高的装饰器逻辑,比如权限验证中获取用户权限的操作,可以进行缓存。
const permissionCache: { [key: string]: boolean } = {};
function checkPermissions(requiredPermissions: string[]) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
const cacheKey = requiredPermissions.join(',');
descriptor.value = function (...args: any[]) {
let hasPermission;
if (permissionCache[cacheKey]) {
hasPermission = permissionCache[cacheKey];
} else {
// 模拟获取当前用户权限
const userPermissions = ['read', 'write'];
hasPermission = requiredPermissions.some(permission => userPermissions.includes(permission));
permissionCache[cacheKey] = hasPermission;
}
if (!hasPermission) {
throw new Error('没有足够权限');
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
- 减少重复计算:避免在装饰器内部进行不必要的重复计算,将一些固定值提前计算好。
3. 避免重复逻辑
- 提取公共逻辑:将权限验证、日志记录等装饰器中的公共逻辑提取到独立的函数或模块中。例如,日志记录装饰器中打印日志的格式可以提取出来。
function formatLog(methodName: string, args: any[], result: any) {
return `调用方法 ${methodName},参数: ${JSON.stringify(args)},返回结果: ${JSON.stringify(result)}`;
}
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const result = originalMethod.apply(this, args);
console.log(formatLog(propertyKey, args, result));
return result;
};
return descriptor;
}
- 使用继承或组合:对于有相似逻辑的装饰器,可以通过继承或组合的方式复用代码。比如,可以创建一个基础装饰器类,其他装饰器继承自它并扩展功能。
4. 在分布式环境下的应用
- 集中式权限管理:使用如Redis等分布式缓存来存储权限信息,各个微服务在权限验证时从Redis中获取最新的权限数据。
import redis from'redis';
const client = redis.createClient();
function checkPermissions(requiredPermissions: string[]) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const userPermissions: string[] = await new Promise((resolve, reject) => {
client.get('userPermissions', (err, reply) => {
if (err) {
reject(err);
} else {
resolve(reply? reply.split(',') : []);
}
});
});
const hasPermission = requiredPermissions.some(permission => userPermissions.includes(permission));
if (!hasPermission) {
throw new Error('没有足够权限');
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
- 分布式日志聚合:使用如ELK(Elasticsearch, Logstash, Kibana)等工具进行日志聚合和分析。各个微服务将日志发送到Logstash,再由Logstash处理后存储到Elasticsearch,最后通过Kibana进行可视化展示。
- 性能监控分布式追踪:引入如Jaeger等分布式追踪系统,在性能监控装饰器中添加追踪ID等信息,以便在分布式环境下跟踪整个业务流程的性能。
import tracer from 'jaeger - client';
function performanceMonitor(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const span = tracer.startSpan(propertyKey);
const start = Date.now();
try {
const result = await originalMethod.apply(this, args);
const end = Date.now();
console.log(`方法 ${propertyKey} 执行时间: ${end - start} ms`);
span.finish();
return result;
} catch (error) {
span.setTag('error', true);
span.finish();
throw error;
}
};
return descriptor;
}
通过以上设计和代码示例,可以基于TypeScript装饰器实现面向切面编程,满足统一的权限验证、日志记录、性能监控等功能,并在性能优化、避免重复逻辑以及分布式环境应用方面有较好的解决方案。