粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • source learn

    • 源码学习
    • 优秀装饰器源码学习(一):time
    • 优秀装饰器源码学习(二)
    • 优秀装饰器源码学习(三)
    • FileSaver.js源码学习,纯前端实现文件下载,防止浏览器直接打开预览
    • 源码学习:MongoDB-ObjectId生成原理
    • 源码学习:Vite中加载环境变量(loadEnv)的实现

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

vuePress-theme-reco 粥里有勺糖    2018 - 2023

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

粥里有勺糖 2021-06-26 技术笔记源码学习

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

# 前言

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

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

根据一些博文的推荐,就选择了core-decorators (opens new window)

# 准备工作

可将源码 (opens new window) clone到本地进行学习

也可直接利用github1s在线预览 (opens new window)

# 搭建测试环境

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

npm install ts-node typescript -g
1

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

tsc --init
1

将noImplicitAny,noImplicitThis设置为false,experimentalDecorators设置为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. */
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

编写示例测试

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

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

ts-node first.ts
1

# 源码目录

图片

简单数了一下大概有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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 执行效果

图片

# console.time实现

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

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

源码中为避免环境不支持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`);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 函数结构

传入参数:

  • 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) {
        
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 最终实现

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)
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 未完待续

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

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

Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34