实践[typescript] 基于装饰器的代码执行器

本次利用装饰器配合require实现装饰器配置自执行ts模块程序。实现本功能的目的是通过指定参数来配置哪些模块运行,该模块主要实现逻辑如下

  1. 扫描指定目录,获取目录下所有ts文件
  2. 判断是否是文件或文件夹
  3. 识别文件或对象中是否包含test函数
  4. @Init识别标记,并决定哪些程序运行

目录结构

arduino 复制代码
.
├── main.ts                入口
├── modules                各种模块
│   ├── config.ts          配置
│   ├── default_modules
│   ├── generator_await
│   ├── stream
│   ├── test.interface.ts
│   ├── test_modules
│   └── thread_model
└── utils                 工具
    ├── decorator.ts      装饰器文件
    └── index.ts

main.ts该文件是整个函数的入口,MODULES变量指定扫描的入口目录

ts 复制代码
import { resolve } from "path";
import { readFile } from "./utils";

const basePath = resolve(__dirname);
const MODULES = "./modules";
(async function () {
  const path = resolve(basePath, MODULES);
  readFile(path);
})();

readFile函数

该函数的主要功能如下

  1. 扫描传入的的路径,若是ts文件,则立即执行,
  2. 否则扫描文件并判断是否应该执行该文件,
  3. 如果是文件夹,则递归执行该函数
  4. 如果是文件,则跳转步骤1
ts 复制代码
/**
 * 运行模块
 * @param modulePath 模块路径
 */
export async function readFile(path: string) {
  const isTsFile = /\.ts$/
  if(await isFile(path)){
    if (isTsFile.test(path)) {
      runCode(path);
    }
    return
  }
  const modules = fs.readdirSync(path);

  for (const item of modules) {
    const modulePath = resolve(path, item);
    if (await isFile(modulePath)) {
      if (!isTsFile.test(item)) {
        continue;
      }
      runCode(modulePath);
    } else {
      await readFile(modulePath);
    }
  }
}

isFile函数

该函数通过对lstat函数进行封装,判断是否是文件夹,用fs.statSync效果是一样的

ts 复制代码
// 判断是否是文件夹
export function isFile(path: string) {
  return new Promise((res) => {
    try {
      fs.lstat(path, (err, stat) => {
        if (err) {
          console.error(err);
          return res(false);
        }
        if (stat.isFile()) {
          res(true);
        } else {
          res(false);
        }
      });
    } catch (e) {
      console.error(e);
      return res(false);
    }
  });
}

runCode函数

该函数的功能是运行传入的经过校验的ts文件,该文件会通过require函数获取ts文件,并判断该文件是函数或默认导出,然后否包含测试运行的test函数,如果包含则表示可运行,具体执行通过装饰器混入的isRun标识是否需要执行,

ts 复制代码
export function runCode(script: string): void {
  const Test = require(script);
  try {
    if (isFunction(Test.test)) {
      Test.test();
    } else if (isFunction(Test.default)) {
      const testObj = new Test.default();
      if (testObj?.test) {
        if (!testObj.isRun) {
          return;
        }
        testObj.test();
      } else if (isFunction(Test)) {
        Test();
      }
    }
  } catch (e) {
    console.error(e);
  }
}

Init装饰器

标识是否需要执行,如果isRun为true,则表示执行,否则不需要执行

ts 复制代码
export function Init(flag:boolean) {
    return function (target:any){
        target.prototype.isRun = flag
    }
}

Test 测试接口类

该类用于为实现了Test接口的类提供自动执行入口

ts 复制代码
export interface Test {
    test():void
}

使用

通过实现test函数标识扫描入口,并通过@Init标识扫描的类是否需要运行

ts 复制代码
import os from 'os'
import { Init } from '../../../utils/decorator';
import { OS } from '../../config';
import type { Test } from '../../test.interface';
@Init(OS)
export default class OsModule implements Test { 
    test ()  {
        console.log('获取芯片架构', os.arch())
        console.log(os.cpus().map(item=>item.speed+'MHZ'));
        console.log(os.devNull);
        console.log('返回内存大小端',os.endianness());
        console.log('返回空闲内存',os.freemem()/1024/1024/8);
        console.log('返回当前进程优先级',os.getPriority());
        console.log('主机名',os.hostname());
        console.log('返回操作系统的平均负载数组,分别是1分钟5分钟 15分钟',os.loadavg());
        // console.log('返回网络接口对象',os.networkInterfaces());
        console.log('返回操作系统的平台字符串',os.platform());
        console.log('返回操作系统',os.release());
        console.log('返回操作系统默认的临时文件目录', os.tmpdir());
        console.log('操作系统内存总量', os.totalmem()/1024/1024/8);
        console.log('返回操作系统的运行时间,单位秒',os.uptime());
        console.log('返回操作系统的用户信息',os.userInfo());
        console.log('返回操作系统的内核版本',os.version());
        console.log('操作系统常量',os.constants);
    }
}

变量OS通过config.ts进行维护

arduino 复制代码
export const OS = true
export const EVENT = false
export const WORK_THREAD = false

export const SQL_GENERATOR= false
export const THREAD = false
export const GENERATOR_AWAIT = false
export const STREAM = false

测试效果

css 复制代码
取芯片架构 x64
[  '3994MHZ', '3989MHZ', '3982MHZ',  '3992MHZ', '3992MHZ', '4000MHZ',  '3997MHZ', '3998MHZ', '3992MHZ',  '3977MHZ', '3985MHZ', '3984MHZ',  '3998MHZ', '3999MHZ', '3998MHZ',  '3999MHZ', '3970MHZ', '3993MHZ',  '3970MHZ', '3985MHZ', '3999MHZ',  '3994MHZ', '3999MHZ', '3999MHZ',  '4000MHZ', '3998MHZ', '3985MHZ',  '3989MHZ', '3999MHZ', '3998MHZ',  '3999MHZ', '3998MHZ']
/dev/null
返回内存大小端 LE
返回空闲内存 2186.59228515625
返回当前进程优先级 0
主机名 XXX-systemproductname
返回操作系统的平均负载数组,分别是1分钟5分钟 15分钟 [ 2.28, 2.83, 2.86 ]
返回操作系统的平台字符串 linux
返回操作系统 6.1.62-1-lts
返回操作系统默认的临时文件目录 /tmp
操作系统内存总量 8025.30126953125
返回操作系统的运行时间,单位秒 1095773.19
返回操作系统的用户信息 {
  uid: 1000,
  gid: 1001,
  username: 'XXX',
  homedir: '/home/XXX',
  shell: '/usr/bin/zsh'
}
返回操作系统的内核版本 #1 SMP PREEMPT_DYNAMIC Thu, 09 Nov 2023 17:21:17 +0000
操作系统常量 [Object: null prototype] {
相关推荐
kidding72310 小时前
前端VUE3的面试题
前端·typescript·compositionapi·fragment·teleport·suspense
来一碗刘肉面1 天前
TypeScript - 属性修饰符
前端·javascript·typescript
Rowrey1 天前
react+typescript,初始化与项目配置
javascript·react.js·typescript
乔冠宇2 天前
微信小程序中将图片截图为正方形(自动居中)
微信小程序·小程序·typescript·uniapp
念九_ysl2 天前
前端循环全解析:JS/ES/TS 循环写法与实战示例
前端·javascript·typescript
MardaWang3 天前
HarmonyOS开发,遇到 Object.assign(this, source)报错怎么解决?
typescript·harmonyos
IT、木易4 天前
TypeScript跟js,es6这些的区别
javascript·typescript·es6
孟陬4 天前
持续改善 React 代码的 SOLID 原则(附带 hooks 详细案例)适用于高级前端
react.js·设计模式·typescript
李二。4 天前
TypeScript学习:初学
typescript
DCTANT5 天前
【原创】vue-element-admin-plus完成编辑页面中嵌套列表功能
前端·javascript·vue.js·elementui·typescript