refactor(dep): 优化性能

This commit is contained in:
roymondchen 2026-03-19 16:02:41 +08:00
parent a34d0cdccc
commit 1664559d8f
3 changed files with 45 additions and 50 deletions

View File

@ -71,7 +71,7 @@ export default class Target {
this.deps[id] = dep; this.deps[id] = dep;
if (dep.keys.indexOf(key) === -1) { if (!dep.keys.includes(key)) {
dep.keys.push(key); dep.keys.push(key);
} }
} }
@ -115,7 +115,7 @@ export default class Target {
public hasDep(id: string | number, key: string | number) { public hasDep(id: string | number, key: string | number) {
const dep = this.deps[id]; const dep = this.deps[id];
return Boolean(dep?.keys.find((d) => d === key)); return dep?.keys.includes(key) ?? false;
} }
public destroy() { public destroy() {

View File

@ -5,6 +5,12 @@ import type Target from './Target';
import { type DepExtendedData, DepTargetType, type TargetList, TargetNode } from './types'; import { type DepExtendedData, DepTargetType, type TargetList, TargetNode } from './types';
import { traverseTarget } from './utils'; import { traverseTarget } from './utils';
const DATA_SOURCE_TARGET_TYPES: Set<string> = new Set([
DepTargetType.DATA_SOURCE,
DepTargetType.DATA_SOURCE_COND,
DepTargetType.DATA_SOURCE_METHOD,
]);
export default class Watcher { export default class Watcher {
private targetsList: TargetList = {}; private targetsList: TargetList = {};
private childrenProp = 'items'; private childrenProp = 'items';
@ -159,7 +165,7 @@ export default class Watcher {
}; };
} }
const clearedItemsNodeIds: (string | number)[] = []; const clearedItemsNodeIds = new Set<string | number>();
traverseTarget(targetsList, (target) => { traverseTarget(targetsList, (target) => {
if (nodes) { if (nodes) {
for (const node of nodes) { for (const node of nodes) {
@ -168,9 +174,9 @@ export default class Watcher {
if ( if (
Array.isArray(node[this.childrenProp]) && Array.isArray(node[this.childrenProp]) &&
node[this.childrenProp].length && node[this.childrenProp].length &&
!clearedItemsNodeIds.includes(node[this.idProp]) !clearedItemsNodeIds.has(node[this.idProp])
) { ) {
clearedItemsNodeIds.push(node[this.idProp]); clearedItemsNodeIds.add(node[this.idProp]);
this.clear(node[this.childrenProp]); this.clear(node[this.childrenProp]);
} }
} }
@ -190,12 +196,7 @@ export default class Watcher {
} }
public collectItem(node: TargetNode, target: Target, depExtendedData: DepExtendedData = {}, deep = false) { public collectItem(node: TargetNode, target: Target, depExtendedData: DepExtendedData = {}, deep = false) {
const dataSourceTargetTypes: string[] = [ if (node[NODE_DISABLE_DATA_SOURCE_KEY] && DATA_SOURCE_TARGET_TYPES.has(target.type)) {
DepTargetType.DATA_SOURCE,
DepTargetType.DATA_SOURCE_COND,
DepTargetType.DATA_SOURCE_METHOD,
];
if (node[NODE_DISABLE_DATA_SOURCE_KEY] && dataSourceTargetTypes.includes(target.type)) {
return; return;
} }

View File

@ -18,6 +18,8 @@ import {
import Target from './Target'; import Target from './Target';
import { DepTargetType, type TargetList } from './types'; import { DepTargetType, type TargetList } from './types';
const INTEGER_REGEXP = /^\d+$/;
export const createCodeBlockTarget = (id: Id, codeBlock: CodeBlockContent, initialDeps: DepData = {}) => export const createCodeBlockTarget = (id: Id, codeBlock: CodeBlockContent, initialDeps: DepData = {}) =>
new Target({ new Target({
type: DepTargetType.CODE_BLOCK, type: DepTargetType.CODE_BLOCK,
@ -30,8 +32,7 @@ export const createCodeBlockTarget = (id: Id, codeBlock: CodeBlockContent, initi
} }
if (value?.hookType === HookType.CODE && Array.isArray(value.hookData)) { if (value?.hookType === HookType.CODE && Array.isArray(value.hookData)) {
const index = value.hookData.findIndex((item: HookData) => item.codeId === id); return value.hookData.some((item: HookData) => item.codeId === id);
return Boolean(index > -1);
} }
return false; return false;
@ -54,12 +55,7 @@ export const isIncludeArrayField = (keys: string[], fields: DataSchema[]) => {
f = field?.fields || []; f = field?.fields || [];
// 字段类型为数组并且后面没有数字索引 // 字段类型为数组并且后面没有数字索引
return ( return field?.type === 'array' && index < keys.length - 1 && !INTEGER_REGEXP.test(keys[index + 1]);
field?.type === 'array' &&
// 不是整数
/^(?!\d+$).*$/.test(`${keys[index + 1]}`) &&
index < keys.length - 1
);
}); });
}; };
@ -78,33 +74,25 @@ export const isDataSourceTemplate = (value: any, ds: Pick<DataSourceSchema, 'id'
return false; return false;
} }
const arrayFieldTemplates = []; for (const tpl of templates) {
const fieldTemplates = [];
templates.forEach((tpl) => {
// 将${dsId.xxxx} 转成 dsId.xxxx // 将${dsId.xxxx} 转成 dsId.xxxx
const expression = tpl.substring(2, tpl.length - 1); const expression = tpl.substring(2, tpl.length - 1);
const keys = getKeysArray(expression); const keys = getKeysArray(expression);
const dsId = keys.shift(); const dsId = keys.shift();
if (!dsId || dsId !== ds.id) { if (!dsId || dsId !== ds.id) {
return; continue;
} }
// ${dsId.array} ${dsId.array[0]} ${dsId.array[0].a} 这种是依赖 // ${dsId.array} ${dsId.array[0]} ${dsId.array[0].a} 这种是依赖
// ${dsId.array.a} 这种不是依赖,这种需要再迭代器容器中的组件才能使用,依赖由迭代器处理 // ${dsId.array.a} 这种不是依赖,这种需要再迭代器容器中的组件才能使用,依赖由迭代器处理
if (isIncludeArrayField(keys, ds.fields)) { const includesArray = isIncludeArrayField(keys, ds.fields);
arrayFieldTemplates.push(tpl); if (hasArray === includesArray) {
} else { return true;
fieldTemplates.push(tpl);
} }
});
if (hasArray) {
return arrayFieldTemplates.length > 0;
} }
return fieldTemplates.length > 0; return false;
}; };
/** /**
@ -184,7 +172,12 @@ export const isDataSourceTarget = (
value: any, value: any,
hasArray = false, hasArray = false,
) => { ) => {
if (!value || !['string', 'object'].includes(typeof value)) { if (!value) {
return false;
}
const valueType = typeof value;
if (valueType !== 'string' && valueType !== 'object') {
return false; return false;
} }
@ -193,13 +186,13 @@ export const isDataSourceTarget = (
} }
// 或者在模板在使用数据源 // 或者在模板在使用数据源
if (typeof value === 'string') { if (valueType === 'string') {
return isDataSourceTemplate(value, ds, hasArray); return isDataSourceTemplate(value, ds, hasArray);
} }
// 关联数据源对象,如:{ isBindDataSource: true, dataSourceId: 'xxx'} // 关联数据源对象,如:{ isBindDataSource: true, dataSourceId: 'xxx'}
// 使用data-source-select value: 'value' 可以配置出来 // 使用data-source-select value: 'value' 可以配置出来
if (isObject(value) && value?.isBindDataSource && value.dataSourceId && value.dataSourceId === ds.id) { if (isObject(value) && value.isBindDataSource && value.dataSourceId === ds.id) {
return true; return true;
} }
@ -210,10 +203,7 @@ export const isDataSourceTarget = (
if (isUseDataSourceField(value, ds.id)) { if (isUseDataSourceField(value, ds.id)) {
const [, ...keys] = value; const [, ...keys] = value;
const includeArray = isIncludeArrayField(keys, ds.fields); const includeArray = isIncludeArrayField(keys, ds.fields);
if (hasArray) { return hasArray ? includeArray : !includeArray;
return includeArray;
}
return !includeArray;
} }
return false; return false;
@ -235,12 +225,9 @@ export const isDataSourceCondTarget = (
return false; return false;
} }
if (ds.fields?.find((field) => field.name === keys[0])) { if (ds.fields?.some((field) => field.name === keys[0])) {
const includeArray = isIncludeArrayField(keys, ds.fields); const includeArray = isIncludeArrayField(keys, ds.fields);
if (hasArray) { return hasArray ? includeArray : !includeArray;
return includeArray;
}
return !includeArray;
} }
return false; return false;
@ -282,12 +269,12 @@ export const createDataSourceMethodTarget = (
return false; return false;
} }
if (ds.methods?.find((method) => method.name === methodName)) { if (ds.methods?.some((method) => method.name === methodName)) {
return true; return true;
} }
// 配置的方法名称可能会是数据源类中定义的并不存在于methods中所以这里判断如果methodName如果是字段名称就表示配置的不是方法 // 配置的方法名称可能会是数据源类中定义的并不存在于methods中所以这里判断如果methodName如果是字段名称就表示配置的不是方法
if (ds.fields?.find((field) => field.name === methodName)) { if (ds.fields?.some((field) => field.name === methodName)) {
return false; return false;
} }
@ -300,11 +287,18 @@ export const traverseTarget = (
cb: (target: Target) => void, cb: (target: Target) => void,
type?: DepTargetType | string, type?: DepTargetType | string,
) => { ) => {
if (type) {
const targets = targetsList[type];
if (targets) {
for (const target of Object.values(targets)) {
cb(target);
}
}
return;
}
for (const targets of Object.values(targetsList)) { for (const targets of Object.values(targetsList)) {
for (const target of Object.values(targets)) { for (const target of Object.values(targets)) {
if (type && target.type !== type) {
continue;
}
cb(target); cb(target);
} }
} }