在TS中如何在子进程中动态实例化一个类

背景:

假设当前有一个主进程A,一个子进程B和一个DemoTask

我们期望的是,在主进程A中通过IPC向子进程B发送一条指令,然后在子进程B中实例化DemoTask,并执行DemoTask中的的逻辑。

在TS中,并没有类似Java反射风格的调用机制,因此需要寻找一种适合TS的动态实例化的方法。

本文主要介绍在子进程B中如何动态实例化DemoTask,不涉及IPC通信的相关内容。

要求:

主进程A中不能import DemoTask,即不能在主进程中加载任何DemoTask的资源。

应该在子进程B中加载DemoTask的相关资源,并执行逻辑。

实现

思想

在子进程中做一个<类名 - 类> 的映射,然后根据"名称 ",找到具体的" ",最后直接"new"即可

举例1:极简实现

ts 复制代码
// DemoTask.ts
// 定义Task
export class DemoTask {
    // 略
}


//////////////////////////////////////////////////////////////////////////////


// TaskRepo.ts
import { DemoTask } from 'DemoTask'

// 关键:注册具体的Task实现类,用于在子进程中实例化具体的Task
// 在子进程中调用
export const TASK_REPO = {}

export function registerTask() {
    TASK_REPO["DemoTask"] = DemoTask;
}


//////////////////////////////////////////////////////////////////////////////


// Demo.ts
import { TASK_REPO } from 'TaskRepo'

// 关键:实例化具体的Task
// 在子进程中调用
export function newTask() {
    let taskInstance = (new TASK_REPO["DemoTask"])();
    
    // 可以调用Task中的具体方法,略...

    return taskInstance
}

关键点:

  1. 在子进程B起来的时候,需要先执行 registerTask(),然后才能执行newTask() 进行实例化
  2. 需要手动维护 TASK_REPO 这个对象:当需要定义新的Task时,需要手动在此处补充Task属性

举例2:结合注解装饰器,实现自动注册

TS 复制代码
// DemoDecorator.ts 
/**
 * 关键:注册具体的Task实现类,用于在子进程中实例化具体的Task
 * 在子进程中调用
 */
export const TASK_REPO = {}

/**
 * 关键:定义注解
 * 该 注解(装饰器)可以向 TASK_REPO 中自动注册Task实现类
 * 在子进程中调用
 */
export function ProcessTask() {
  return (target): void => {
    TASK_REPO[target.name] = target;
  };
}


/////////////////////////////////////////////////////////////////////////////////////


// DemoTask.ts
// 定义Task:使用装饰器,实现自动注册Task
@ProcessTask()
export class DemoTask {
    // 略
}


/////////////////////////////////////////////////////////////////////////////////////


// Demo.ts
// 关键:实例化具体的Task
// 在子进程中调用
export function newTask() {
    let taskInstance = (new TASK_REPO["DemoTask"])();
    
    // 可以调用Task中的具体方法,略...

    return taskInstance
}

关于这个例子需要进一步讨论:

  • Q:在子进程中,类装饰器为什么没有触发执行?
    A:当加载DemoTask类时,会自动触发类装饰器;若没有触发类装饰器,说明DemoTask没有被加载到该进程。

  • Q:那该怎么办?
    A:在进程起来的时候执行一段"携带该Task的import代码 ",如,打印该Task的类名

    TS 复制代码
    import {DemoTask} from DemoTask.ts
    
    export const TASK_LOADER = [
      DemoTask
    ]
    
    // 在 子进程B 起来时,先调用执行这一段代码
    export function printDetail() {
      let array = PAF_TASK_LOADER  
      let taskNames = ""
      for (let task of array) {
        taskNames += (task.name) + " ## "
      }
      Logger.info(TAG, "succeed loading TASK. detail: length=" + array.length + " taskNames=" + taskNames)
    }
  • Q:"携带该Task的import代码"需要手写?
    A:可以开发"编译插件",在编译阶段自动生成上述代码

  • Q:那在"举例1"的基础上直接开发"编译插件",实现自动注册,岂不是更简单
    A:是的。但是引入装饰器,既可以在未来扩展DemoTask的功能,同时也不会使"编译插件"开发得过于复杂

相关推荐
暗冰ཏོ9 分钟前
Spring Boot + Vue3 订单支付模块技术实现:支付单、回调验签、幂等处理与余额扣减
前端·spring boot·后端·vue·微信支付·支付宝支付
Csvn11 分钟前
AbortController 不止能取消 Fetch!3 个你不知道的隐藏用法
前端·javascript
爷_18 分钟前
AI Coding Agent 沙箱的设计原理解析
前端·人工智能·后端
爱勇宝20 分钟前
第 3 章:别把团队设计成一场内卷竞赛
前端·后端·程序员
蜡台38 分钟前
修改Uniapp input 组件不刷新视图问题
前端·uni-app·input
逸铭42 分钟前
Day 8:Preload 是什么?——在别人的网页里打黑工还要合规
前端·客户端
柒和远方1 小时前
Worker Readiness:为什么 `/health` 不能证明后台任务能跑
前端·后端·架构
吃糖的小孩1 小时前
Web Owner Console 还没写前端,我先给它设计 read model
前端
析数塔1 小时前
2026前端框架深度解析:React Compiler、Angular Zoneless、Vue 3.5重写游戏规则
前端·vue.js·react.js