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

相关推荐
诗书画唱2 分钟前
【前端面试题】JavaScript 核心知识点解析(第二十二题到第六十一题)
开发语言·前端·javascript
excel8 分钟前
前端必备:从能力检测到 UA-CH,浏览器客户端检测的完整指南
前端
前端小巷子15 分钟前
Vue 3全面提速剖析
前端·vue.js·面试
悟空聊架构22 分钟前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
CodeSheep23 分钟前
国内 IT 公司时薪排行榜。
前端·后端·程序员
尖椒土豆sss27 分钟前
踩坑vue项目中使用 iframe 嵌套子系统无法登录,不报错问题!
前端·vue.js
遗悲风28 分钟前
html二次作业
前端·html
江城开朗的豌豆31 分钟前
React输入框优化:如何精准获取用户输入完成后的最终值?
前端·javascript·全栈
CF14年老兵32 分钟前
从卡顿到飞驰:我是如何用WebAssembly引爆React性能的
前端·react.js·trae
画月的亮35 分钟前
前端处理导出PDF。Vue导出pdf
前端·vue.js·pdf