You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现TypeScript类装饰器自动为所有方法添加计时功能

TypeScript 类装饰器自动为普通方法添加计时日志

1. 单个方法的计时装饰器 TimeDebug

先确认单个方法的计时装饰器实现,这是核心基础:

function TimeDebug(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`方法 ${propertyKey} 执行耗时: ${(end - start).toFixed(2)}ms`);
    return result;
  };

  return descriptor;
}

2. 类装饰器 TimeMethods 实现

接下来实现类装饰器,自动遍历类的所有普通方法,排除 getter、属性、构造函数等,给符合条件的方法批量加上TimeDebug:

function TimeMethods() {
  return function (constructor: Function) {
    // 遍历类原型上的所有属性名
    Object.getOwnPropertyNames(constructor.prototype).forEach((propertyKey) => {
      const descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, propertyKey);
      
      // 过滤规则:是普通方法(有value属性且为函数)、不是构造函数
      if (descriptor && typeof descriptor.value === 'function' && propertyKey !== 'constructor') {
        // 给目标方法应用计时装饰器
        TimeDebug(constructor.prototype, propertyKey, descriptor);
        // 更新原型上的方法描述符
        Object.defineProperty(constructor.prototype, propertyKey, descriptor);
      }
    });
  };
}

3. 使用示例

用给定的MyClass测试效果:

@TimeMethods()
class MyClass {
  private _foo: string = 'bar';

  get foo() {
    return this._foo;
  }

  printX(x: string) {
    console.log(`输出: ${x}`);
    // 模拟耗时操作
    for (let i = 0; i < 10000000; i++) {}
  }

  add(a: number, b: number): number {
    // 模拟耗时操作
    for (let i = 0; i < 5000000; i++) {}
    return a + b;
  }
}

// 测试执行
const instance = new MyClass();
instance.printX('Hello TypeScript');
console.log(instance.add(10, 20));
console.log(instance.foo); // getter不会被添加计时日志

4. 扩展:排除指定普通方法

如果需要跳过某些不需要计时的普通方法,可以给TimeMethods添加参数,指定排除列表:

function TimeMethods(excludeMethods: string[] = []) {
  return function (constructor: Function) {
    Object.getOwnPropertyNames(constructor.prototype).forEach((propertyKey) => {
      // 跳过指定排除的方法
      if (excludeMethods.includes(propertyKey)) return;
      
      const descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, propertyKey);
      if (descriptor && typeof descriptor.value === 'function' && propertyKey !== 'constructor') {
        TimeDebug(constructor.prototype, propertyKey, descriptor);
        Object.defineProperty(constructor.prototype, propertyKey, descriptor);
      }
    });
  };
}

// 使用时排除add方法
@TimeMethods(['add'])
class MyClass {
  // ... 类内容同上
}

关键逻辑说明

  • 类装饰器通过遍历类的prototype属性,获取每个属性的描述符,以此区分普通方法和getter(getter的描述符没有value,而是有get属性)。
  • 自动跳过constructor,避免修改类的构造逻辑,确保只有业务普通方法被添加计时日志。

内容的提问来源于stack exchange,提问作者Wouter Vandenputte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:05:19