优秀装饰器源码学习(一):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函数

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

相关文章
|
9月前
|
测试技术 API
harfbuzz 的用法
HarfBuzz 整形 API 的核心是函数。此函数采用一种字体,即 包含一串 Unicode 代码点的缓冲区和 (可选)字体功能列表作为其输入。它取代了 缓冲区中的代码点,其中包含来自 字体,正确排序和定位,以及任何 应用的可选字体功能。hb_shape()
247 0
|
11月前
|
Java Spring
@ConditionalOnProperty的用法
@ConditionalOnProperty的用法
243 0
|
C# 容器 数据格式
AvalonDock的基本用法
原文:AvalonDock的基本用法         AvalonDock是优秀的开源项目,用于创建可停靠式布局,能够在WPF中方便开发出类似VS2010的软件界面。对于复杂的软件系统,大量控件的使用会使的界面变得难以管理。
2056 0
iTween的基本用法
Unity3D插件-iTween的基本用法 本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例...
1857 0
EasyTouch基本用法
EasyTouch基本用法 本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) ...
1477 0
|
JavaScript 前端开发 C#