MST

星途 面试题库

面试题:TypeScript方法装饰器在复杂业务场景下的性能优化与日志记录综合应用

在一个具有多个服务层相互调用的复杂前端应用场景中,部分方法调用十分频繁且对性能要求高,同时需要详细的日志记录用于调试和监控。请设计一套基于TypeScript方法装饰器的方案,既能实现对这些频繁调用方法的性能优化(如合理的缓存策略、异步处理等),又能保证全面且准确的日志记录(包括调用链追踪、参数和返回值记录等),并详细阐述设计思路与关键代码实现。
26.9万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 性能优化
    • 缓存策略:对于频繁调用且输入参数相同会得到相同结果的方法,使用缓存来避免重复计算。可以使用一个Map来存储方法调用的输入参数和对应的返回值。
    • 异步处理:对于一些可以异步执行的任务,使用async/await或者Promise将其异步化,避免阻塞主线程。
  2. 日志记录
    • 调用链追踪:为每个请求生成一个唯一的标识符(例如uuid),在整个调用链中传递这个标识符,记录日志时带上它,方便追踪整个请求的流程。
    • 参数和返回值记录:在方法调用前后记录方法的输入参数和返回值,便于调试和分析。

关键代码实现

  1. 安装依赖
    • 首先需要安装uuid库用于生成唯一标识符,在项目目录下执行npm install uuid
  2. 定义装饰器
import { v4 as uuidv4 } from 'uuid';

// 缓存装饰器
function cache(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    const cacheMap = new Map();
    descriptor.value = function (...args: any[]) {
        const key = args.toString();
        if (cacheMap.has(key)) {
            return cacheMap.get(key);
        }
        const result = originalMethod.apply(this, args);
        cacheMap.set(key, result);
        return result;
    };
    return descriptor;
}

// 日志记录装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = async function (...args: any[]) {
        const requestId = uuidv4();
        console.log(`[${requestId}] Start calling method ${propertyKey} with args:`, args);
        try {
            const result = await originalMethod.apply(this, args);
            console.log(`[${requestId}] Method ${propertyKey} returned:`, result);
            return result;
        } catch (error) {
            console.error(`[${requestId}] Method ${propertyKey} error:`, error);
            throw error;
        }
    };
    return descriptor;
}

// 组合装饰器
function performanceAndLog(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    cache(target, propertyKey, descriptor);
    return log(target, propertyKey, descriptor);
}
  1. 使用装饰器
class MyService {
    @performanceAndLog
    async expensiveCalculation(a: number, b: number): Promise<number> {
        // 模拟一些耗时操作
        await new Promise(resolve => setTimeout(resolve, 1000));
        return a + b;
    }
}

const myService = new MyService();
myService.expensiveCalculation(1, 2).then(result => {
    console.log('Final result:', result);
});

在上述代码中:

  • cache装饰器实现了简单的缓存策略,根据方法的输入参数缓存返回值。
  • log装饰器生成唯一的请求ID,记录方法调用的开始、结束以及错误信息,实现调用链追踪和参数、返回值记录。
  • performanceAndLog装饰器组合了cachelog装饰器,先进行缓存优化,再进行日志记录。在MyService类的expensiveCalculation方法上使用performanceAndLog装饰器,该方法就同时具备了性能优化和日志记录的功能。