本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本文将编写一个计算同步和异步method执行时间的方法装饰器
🥑 在typescript下启用装饰器
如果要在typescript下使用decorator, 首先需要在tsconfig.json 添加如下options:
"compilerOptions": {
"emitDecoratorMetadata": true, // optional, 使Reflect类可以添加或读取metadata
"experimentalDecorators": true, // required
}
复制代码
🥑 方法装饰器(Method decorator)的参数定义
方法装饰器在执行时会获得三个参数:target, propertyKey和descriptor
- target: 当前对象的原型,假设 TestClass 是对象,那么 target 就是 TestClass.prototype
- propertyKey: 方法的名称
- descriptor: 方法的属性描述符,即 Object.getOwnPropertyDescriptor(TestClass.prototype, propertyKey)
// typescript定义
type MethodDecorator = <T>(
target: Object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<T>
) => TypedPropertyDescriptor<T> | void
复制代码
🥑 编写一个计算执行时间的装饰器 - 同步方法(sync method)
首先我们先定义用于计算同步method的装饰器
export const logExecutionTimeSync = () => {
return function (
target : Object,
propertyKey : string | symbol,
propertyDescriptor : PropertyDescriptor,
) {
const originalFunc = propertyDescriptor.value;
// 修改原有function的定义
propertyDescriptor.value = function (...args : any[]) {
const startTime = new Date().getTime();
const results = originalFunc.apply(this, args);
const endTime = new Date().getTime();
console.log(
`*** ${propertyKey} took ${
endTime - startTime
} msec to run ***`,
);
return results;
};
return propertyDescriptor;
};
};
复制代码
接着定义一个测试用的method, 可以直接引入decorator使用
class TestClass {
// 没有参数时 可以省略括号
@logExecutionTimeSync
function testFunctionSync() {
console.log('logExecutionTimeSync() runs immediately');
}
}
复制代码
输出结果
logExecutionTimeSync() runs immediately
*** logExecutionTimeSync took 0 msec to run ***
复制代码
🥑 编写一个计算执行时间的装饰器 - 异步方法(async method)
对于异步的method, 只需要在执行原有function时使用await即可
export const logExecutionTimeAsync = () => {
return function (
target : Object,
propertyKey : string | symbol,
propertyDescriptor : PropertyDescriptor,
) {
const originalFunc = propertyDescriptor.value;
// 修改原有function的定义
propertyDescriptor.value = async function (...args : any[]) {
const startTime = new Date().getTime();
const results = await originalFunc.apply(this, args);
const endTime = new Date().getTime();
console.log(
`*** ${propertyKey} took ${
endTime - startTime
} msec to run ***`,
);
return results;
};
return propertyDescriptor;
};
};
复制代码
接着定义一个测试的异步method, 可以直接引入decorator使用
class TestClass {
@logExecutionTimeAsync()
async function testFunctionAsync() {
// 定义一个timeout方法 可以让程序等待一段时间后继续执行
const timeout = new Promise((resolve) => setTimeout(resolve, ms));
await timeout(2000);
console.log('testFunction() runs after 2s');
}
}
复制代码
输出结果
testFunctionAsync() runs after 2s
*** testFunctionAsync took 2003 msec to run ***
复制代码
🥑 方法装饰器接收参数
我们之前定义的装饰器也可以接受参数, 不过参数是静态的 将会在编译时就传入装饰器
// 参数是静态的 将会在编译时就传入装饰器
@logExecutionTimeAsync('param1', 'param2')
const logExecutionTimeAsync = (param1, param2) => {
}
复制代码