roymondchen 4bbda354a9 feat(editor,dep): collectIdle 使用常驻 Web Worker 做依赖收集
将节点树遍历与 target 匹配下沉到与 collectByWorker 共用的常驻 worker,
避免大页面时主线程卡死;通过可序列化 descriptor 重建内置 target,
失败时回退主线程空闲队列。
2026-07-30 17:03:48 +08:00

130 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { DepData } from '@tmagic/schema';
import { DepTargetType, type IsTarget, type TargetDescriptor, type TargetOptions } from './types';
export interface DepUpdateOptions {
id: string | number;
name: string;
key: string | number;
data: Record<string, any>;
}
/**
* 需要收集依赖的目标
* 例如:一个代码块可以为一个目标
*/
export default class Target {
/**
* 如何识别目标
*/
public isTarget: IsTarget;
/**
* 目标id不可重复
* 例如目标是代码块则为代码块id
*/
public id: string | number;
/**
* 目标名称,用于显示在依赖列表中
*/
public name?: string;
/**
* 不同的目标可以进行分类例如代码块数据源可以为两个不同的type
*/
public type: string = DepTargetType.DEFAULT;
/**
* 依赖详情
* 实例:{ 'node_id': { name: 'node_name', keys: [ created, mounted ] } }
*/
public deps: DepData = {};
/**
* 是否默认收集默认为true当值为false时需要传入type参数给collect方法才会被收集
*/
public isCollectByDefault?: boolean;
/**
* 可序列化描述,有该描述的 target 可以在 worker 中重建,从而把依赖收集放到子线程执行
*/
public descriptor?: TargetDescriptor;
constructor(options: TargetOptions) {
this.isTarget = options.isTarget;
this.id = options.id;
this.name = options.name;
this.isCollectByDefault = options.isCollectByDefault ?? true;
this.descriptor = options.descriptor;
if (options.type) {
this.type = options.type;
}
if (options.initialDeps) {
this.deps = options.initialDeps;
}
}
/**
* 更新依赖
* @param option 节点配置
* @param key 哪个key配置了这个目标的id
*/
public updateDep({ id, name, key, data }: DepUpdateOptions) {
const dep = this.deps[id] || {
name,
keys: [],
};
dep.name = name;
dep.data = data;
this.deps[id] = dep;
if (!dep.keys.includes(key)) {
dep.keys.push(key);
}
}
/**
* 删除依赖
* @param node 哪个节点的依赖需要移除,如果为空,则移除所有依赖
* @param key 节点下哪个key需要移除如果为空则移除改节点下的所有依赖key
* @returns void
*/
public removeDep(id?: string | number, key?: string | number) {
if (typeof id === 'undefined') {
Object.keys(this.deps).forEach((depKey) => {
delete this.deps[depKey];
});
return;
}
const dep = this.deps[id];
if (!dep) return;
if (key) {
const index = dep.keys.indexOf(key);
dep.keys.splice(index, 1);
if (dep.keys.length === 0) {
delete this.deps[id];
}
} else {
delete this.deps[id];
}
}
/**
* 判断指定节点下的指定key是否存在在依赖列表中
* @param node 哪个节点
* @param key 哪个key
* @returns boolean
*/
public hasDep(id: string | number, key: string | number) {
const dep = this.deps[id];
return dep?.keys.includes(key) ?? false;
}
public destroy() {
this.deps = {};
}
}