在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的功能,同时也不会使"编译插件"开发得过于复杂

相关推荐
deli0073 分钟前
手机20%突然关机?电量百分比是估的,SOC曲线4组实测
前端
深蓝AI10 小时前
Meta 开源用了八年的设计系统 astryx:连坐两天 GitHub 总榜第一,组件库开始写给 agent 的说明书
前端·人工智能
IT_陈寒11 小时前
Vue的watch把我坑惨了,原来要这样用才靠谱
前端·人工智能·后端
1-1=011 小时前
Vue 3 模板语
前端·javascript·vue.js
用户76103044737111 小时前
【转战智能眼镜开发】ROKID AIUI 小游戏 亚马逊标枪项目实战讲解
前端
风卿12 小时前
看着AI写代码太孤独了,来欣赏星云吧:一个DSH 装饰插件
前端·javascript
牧艺12 小时前
弹层不用再手算坐标了:CSS Anchor Positioning 从原理到可上线
前端·javascript·css
用户老李12 小时前
YOLO 目标检测自学教程 07:YOLOv3——多尺度预测
前端
moshuying12 小时前
ESP32 墨水屏金价牌(上):从点亮到把图片推过去
前端
李剑一13 小时前
别再抬杠,前端岗已经没了!无论前后端,我们最终都要成“全干”工程师
前端·面试