perf: 优化智能体与工作流幕布渲染性能
- 分阶段加载智能体配置并按需缓存 MCP 工具 - 合并画布状态更新与节点尺寸监听,启用大图可视区域渲染和静态连线 - 隔离 Tinyflow Store 实例并补充数据同步与回归测试
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {Tinyflow as TinyflowNative, TinyflowOptions} from '@tinyflow-ai/ui';
|
||||
import type { TinyflowOptions } from '@tinyflow-ai/ui';
|
||||
|
||||
import { Tinyflow as TinyflowNative } from '@tinyflow-ai/ui';
|
||||
import '@tinyflow-ai/ui/dist/index.css';
|
||||
import {
|
||||
getCurrentInstance,
|
||||
@@ -15,8 +17,7 @@ import {
|
||||
watch,
|
||||
} from 'vue';
|
||||
|
||||
type TinyflowDataOption = Exclude<TinyflowOptions['data'], string | undefined>;
|
||||
type StructuredCloneFn = <T>(value: T) => T;
|
||||
import { createTinyflowDataSync } from './dataSync';
|
||||
|
||||
const props = defineProps<
|
||||
{
|
||||
@@ -30,7 +31,7 @@ const attrs = useAttrs();
|
||||
const instance = getCurrentInstance();
|
||||
let tinyflow: TinyflowNative | null = null;
|
||||
let mountedDataReady = false;
|
||||
let lastAppliedDataSignature = '';
|
||||
const dataSync = createTinyflowDataSync();
|
||||
const optionalBooleanOptionKeys = new Set([
|
||||
'readonly',
|
||||
'hideBottomDock',
|
||||
@@ -45,6 +46,7 @@ const optionalBooleanOptionKeys = new Set([
|
||||
'nodesDraggable',
|
||||
'nodesConnectable',
|
||||
'elementsSelectable',
|
||||
'onlyRenderVisibleElements',
|
||||
'dropEnabled',
|
||||
]);
|
||||
|
||||
@@ -81,58 +83,6 @@ function normalizeProps(source: Record<string, unknown>) {
|
||||
);
|
||||
}
|
||||
|
||||
// 安全深拷贝工具函数
|
||||
function safeDeepClone<T>(obj: T): T {
|
||||
if (obj === null || typeof obj !== 'object') return obj;
|
||||
|
||||
try {
|
||||
const clone = (globalThis as { structuredClone?: StructuredCloneFn })
|
||||
.structuredClone;
|
||||
if (clone) {
|
||||
return clone(obj);
|
||||
}
|
||||
} catch {
|
||||
// Fall through to JSON cloning for browsers without native structuredClone.
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
} catch {
|
||||
try {
|
||||
console.warn(
|
||||
'Failed to clone object, returning original (may cause issues)',
|
||||
obj,
|
||||
);
|
||||
return obj;
|
||||
} catch {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createDataSignature(data: unknown) {
|
||||
if (data == null || typeof data === 'string') {
|
||||
return String(data ?? '');
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(data);
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function cloneDataIfChanged(data: TinyflowOptions['data']) {
|
||||
if (data == null || typeof data === 'string') {
|
||||
return null;
|
||||
}
|
||||
const signature = createDataSignature(data);
|
||||
if (signature && signature === lastAppliedDataSignature) {
|
||||
return null;
|
||||
}
|
||||
lastAppliedDataSignature = signature;
|
||||
return safeDeepClone(data as TinyflowDataOption);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (divRef.value) {
|
||||
// 净化 props.data,避免响应式对象或函数污染
|
||||
@@ -141,8 +91,21 @@ onMounted(() => {
|
||||
...normalizeProps(props),
|
||||
} as any;
|
||||
if ('data' in cleanedProps && cleanedProps.data != null) {
|
||||
cleanedProps.data = cloneDataIfChanged(cleanedProps.data);
|
||||
cleanedProps.data = dataSync.cloneExternalDataIfChanged(cleanedProps.data);
|
||||
}
|
||||
(['onDataChange', 'onDataCommit'] as const).forEach((callbackKey) => {
|
||||
const callback = cleanedProps[callbackKey];
|
||||
if (typeof callback !== 'function') {
|
||||
return;
|
||||
}
|
||||
cleanedProps[callbackKey] = (
|
||||
data: TinyflowOptions['data'],
|
||||
...args: unknown[]
|
||||
) => {
|
||||
dataSync.markNativeData(data);
|
||||
callback(data, ...args);
|
||||
};
|
||||
});
|
||||
|
||||
tinyflow = new TinyflowNative({
|
||||
...cleanedProps,
|
||||
@@ -158,7 +121,7 @@ onUnmounted(() => {
|
||||
tinyflow = null;
|
||||
}
|
||||
mountedDataReady = false;
|
||||
lastAppliedDataSignature = '';
|
||||
dataSync.reset();
|
||||
});
|
||||
|
||||
watch(
|
||||
@@ -179,7 +142,7 @@ watch(
|
||||
data != null &&
|
||||
typeof data !== 'string'
|
||||
) {
|
||||
const clonedData = cloneDataIfChanged(data);
|
||||
const clonedData = dataSync.cloneExternalDataIfChanged(data);
|
||||
if (clonedData) {
|
||||
tinyflow.updateData(clonedData, { preserveViewport: true });
|
||||
}
|
||||
@@ -229,7 +192,7 @@ const updateData = (
|
||||
options?: { preserveViewport?: boolean },
|
||||
) => {
|
||||
if (tinyflow && data != null && typeof data !== 'string') {
|
||||
const clonedData = cloneDataIfChanged(data);
|
||||
const clonedData = dataSync.cloneExternalDataIfChanged(data);
|
||||
if (!clonedData) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user