优秀装饰器源码学习(一):time

简介: 优秀装饰器源码学习(一):time

前言


最近又温习了一遍TS装饰器,准备用装饰器改造一下自己的轮子

在改造之前,准备先学习一下优秀的装饰器开源库,站在巨人的肩膀上前行

根据一些博文的推荐,就选择了core-decorators


准备工作


可将源码 clone到本地进行学习

也可直接利用github1s在线预览


搭建测试环境


全局安装ts-node与typescript两个依赖


npm install ts-node typescript -g


初始化ts配置文件(tsconfig.json)


tsc --init


noImplicitAny,noImplicitThis设置为falseexperimentalDecorators设置为true


{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */
    "target": "es5",                              
    "lib": ["ESNext","DOM"], 
    /* Strict Type-Checking Options */
    "strict": true,                                 /* Enable all strict type-checking options. */
    "noImplicitAny": false,                       
    "noImplicitThis": false,                      /* Raise error on 'this' expressions with an implied 'any' type. */
    "esModuleInterop": true,                        /* Enables emit interoperability between CommonJS and ES Modules via 
    /* Experimental Options */
    "experimentalDecorators": true,              /* Enables experimental support for ES7 decorators. */
    /* Advanced Options */
    "skipLibCheck": true,                           /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
  }
}


编写示例测试


function defaultValue(str:string){
    return function(target,property){
        target[property] = str
    }
}
class User {
    @defaultValue('666')
    private _name: string | undefined
    constructor(name?:string) {
        if(name){
            this._name = name
        }
    }
    get name(){
        return this._name
    }
}
const a = new User()
console.log(a.name); // 666


运行,结果如上述的注释所示


ts-node first.ts


源码目录


网络异常,图片无法展示
|


简单数了一下大概有17个,咱一个个的挨着学,细细品


下面开始和大家一起学,由易到难


time


用于计算一个函数执行耗时


使用示例


使用如下,通过一个简单的 @time 即可让函数执行完后打印执行时间


import { time } from './../index'
class Test {
    @time()
    sayHello() {
        let i = 0
        while (i < 100000) {
            i++
        }
        console.log('success');
    }
}
const t = new Test()
t.sayHello()


执行效果


网络异常,图片无法展示
|


console.time实现


计算程序的执行时间可以利用console.timeconsole.timeEnd实现


console.time('label')
// ...code 
console.timeEnd('label') // 即可打印出执行耗时


源码中为避免环境不支持console.time/timeEnd,巧妙实现了一下,源码如下


const labels = {}
// 替代console.time
const myTime = (label) => {
    // 记录开始时间
    labels[label] = new Date().getTime()
}
// 替代console.timeEnd
const myTimeEnd = (label) => {
    const timeNow = new Date().getTime();
    // 当前时间与开始时间做差
    const timeTaken = timeNow - labels[label];
    // 删除无用的标志
    delete labels[label];
    // 打印耗时
    console.log(`${label}: ${timeTaken}ms`);
}


函数结构


传入参数:

  • prefix:默认null
  • 自定义console:默认使用内建的console.time/timeEnd


// 首先是console.time的polyfill
// 当没定义time与timeEnd的时候,利用labels变量实现类似的效果
const defaultConsole = {
    time: console.time ? console.time.bind(console) : myTime,
    timeEnd: console.timeEnd ? console.timeEnd.bind(console) : myTimeEnd
}
// 用于label生成
let count = 0
export default function time(prefix: null | string = null, console = defaultConsole) {
    return function (target, key, descriptor) {
    }
}


最终实现


let count = 0
export default function time(prefix: null | string = null, console = defaultConsole) {
    return function (target, key, descriptor) {
        const fn = descriptor.value
        // 如果没有传参
        // 使用构造函数的名称与装饰对象的属性名作为key
        if (prefix === null) {
            prefix = `${target.constructor.name}.${key}`;
        }
        // 校验装饰对象是否为函数
        if (typeof fn !== 'function') {
            throw new SyntaxError(`@time can only be used on functions, not: ${fn}`);
        }
        return {
            ...descriptor,
            value() {
                const label = `${prefix}-${count}`
                count++
                console.time(label)
                try {
                    return fn.apply(this, arguments)
                } finally {
                    console.timeEnd(label)
                }
            }
        }
    }
}


未完待续


本文主要介绍了测试环境的搭建,跟着源码一起重现了time函数

后续文章将直接对源码进行分析与学习

相关文章
|
6月前
|
Python
Python用装饰器实现函数计时功能。
【2月更文挑战第11天】【2月更文挑战第29篇】Python用装饰器实现函数计时功能。
61 0
|
3月前
|
数据处理 Python
Python使用装饰器记录函数执行时间
Python使用装饰器记录函数执行时间
49 0
|
6月前
|
测试技术 开发者 Python
Python中的装饰器(Decorators)原理与应用解析
在Python编程中,装饰器(Decorators)是一种强大的工具,能够灵活地扩展函数或类的功能,提高代码的可复用性和可维护性。本文将深入探讨装饰器的原理、使用方法以及常见应用场景,帮助读者更好地理解和运用这一重要的Python特性。
|
存储 Python
Python装饰器2-__call__方法与类装饰器
__call__方法、创建类装饰器、装饰器的应用场景
Python装饰器2-__call__方法与类装饰器
|
6月前
|
数据安全/隐私保护 Python
解释装饰器(decorator)的功能和用法。
解释装饰器(decorator)的功能和用法。
52 1
|
Unix Python
Python编程:time时间模块
Python编程:time时间模块
195 0
Python编程:time时间模块
|
Python
Python编程:time和datetime时间模块详解
Python编程:time和datetime时间模块详解
206 0
Python编程:time和datetime时间模块详解
|
Python
【透彻】Python装饰器进阶(类装饰器+带参数的装饰器+多装饰器)| Python 主题月
【透彻】Python装饰器进阶(类装饰器+带参数的装饰器+多装饰器)| Python 主题月
164 0
优秀装饰器源码学习(二)
优秀装饰器源码学习(二)
|
数据采集 Python
Python---闭包、函数作为参数传递、装饰器-----进阶必备,不必再为弄不清而烦恼
Python---闭包、函数作为参数传递、装饰器-----进阶必备,不必再为弄不清而烦恼
124 0