fix: autoflow not rerun if render by render function directly

This commit is contained in:
gchust 2025-06-22 12:57:27 +08:00
parent c6e9e9ba79
commit b643c9a330
3 changed files with 71 additions and 83 deletions

View File

@ -309,4 +309,13 @@ export class FlowEngine {
}
return modelClasses;
}
static generateApplyFlowCacheKey(
prefix: string,
flowKey: string,
modelUid: string,
params: Record<string, any>,
): string {
return `${prefix}:${flowKey}:${modelUid}:${JSON.stringify(params)}`;
}
}

View File

@ -13,77 +13,7 @@ import { FlowModel } from '../models';
import { useFlowEngine } from '../provider';
import { FlowExtraContext } from '../types';
import { uid } from 'uid/secure';
// 生成稳定的缓存键
function generateCacheKey(prefix: string, flowKey: string, modelUid: string): string {
return `${prefix}:${flowKey}:${modelUid}`;
}
// 安全序列化对象的函数
function safeStringify(obj: any, visited = new Set(), depth = 0, maxDepth = 5): string {
// 深度限制,防止过深递归
if (depth > maxDepth) {
return '[MaxDepthExceeded]';
}
// 处理基本类型
if (obj === null || obj === undefined) {
return String(obj);
}
if (typeof obj !== 'object' && typeof obj !== 'function') {
return String(obj);
}
// 处理函数
if (typeof obj === 'function') {
// 对于函数,可以使用函数名或为匿名函数生成一个标识符
return `function:${obj.name || 'anonymous'}`;
}
// 处理循环引用
if (visited.has(obj)) {
return '[Circular]';
}
// 添加到已访问集合
visited.add(obj);
// 处理数组
if (Array.isArray(obj)) {
try {
// 限制处理的数组元素数量
const maxItems = 100;
const items = obj.slice(0, maxItems);
const result =
'[' +
items.map((item) => safeStringify(item, visited, depth + 1, maxDepth)).join(',') +
(obj.length > maxItems ? ',...' : '') +
']';
return result;
} catch (e) {
return '[Array]';
}
}
// 处理普通对象
try {
const keys = Object.keys(obj).sort(); // 排序确保稳定性
// 限制处理的属性数量
const maxKeys = 50;
const limitedKeys = keys.slice(0, maxKeys);
const pairs = limitedKeys.map((key) => {
const value = obj[key];
return `${key}:${safeStringify(value, visited, depth + 1, maxDepth)}`;
});
return '{' + pairs.join(',') + (keys.length > maxKeys ? ',...' : '') + '}';
} catch (e) {
// 如果无法序列化,返回一个简单的标识
return '[Object]';
}
}
import { FlowEngine } from '../flowEngine';
/**
* Hook
@ -105,8 +35,8 @@ function useFlowExecutor<T, TModel extends FlowModel = FlowModel>(
): T {
const engine = useFlowEngine();
const cacheKey = useMemo(
() => generateCacheKey(model['forkId'] ?? cacheKeyPrefix, flowKey, model.uid),
[cacheKeyPrefix, flowKey, model.uid, model['forkId']],
() => FlowEngine.generateApplyFlowCacheKey(model['forkId'] ?? cacheKeyPrefix, flowKey, model.uid, model.stepParams),
[cacheKeyPrefix, flowKey, model.uid, model['forkId'], model.stepParams],
);
const [, forceUpdate] = useState({});
const isMounted = useRef(false);

View File

@ -325,6 +325,7 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
}
}
}
this.applyAutoFlows(); // 参数变化时自动重新执行 autoFlows
}
getStepParams(flowKey: string, stepKey: string): any | undefined;
@ -518,9 +519,10 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
/**
*
* @param {FlowExtraContext} [extra]
* @param {boolean} [useCache=true] 使 true
* @returns {Promise<any[]>}
*/
async applyAutoFlows(extra?: FlowExtraContext): Promise<any[]> {
async applyAutoFlows(extra?: FlowExtraContext, useCache = true): Promise<any[]> {
const autoApplyFlows = this.getAutoFlows();
if (autoApplyFlows.length === 0) {
@ -528,6 +530,26 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
return [];
}
// 生成缓存键,包含 stepParams 的序列化版本以确保参数变化时重新执行
const cacheKey = useCache
? FlowEngine.generateApplyFlowCacheKey(this['forkId'] ?? 'autoFlow', 'all', this.uid, this.stepParams)
: null;
// 检查缓存
if (cacheKey && this.flowEngine) {
const cachedEntry = this.flowEngine.applyFlowCache.get(cacheKey);
if (cachedEntry) {
if (cachedEntry.status === 'resolved') {
console.log(`[FlowEngine.applyAutoFlows] Using cached result for model: ${this.uid}`);
return cachedEntry.data;
}
if (cachedEntry.status === 'rejected') throw cachedEntry.error;
if (cachedEntry.status === 'pending') return await cachedEntry.promise;
}
}
// 执行 autoFlows
const executeAutoFlows = async (): Promise<any[]> => {
const results: any[] = [];
for (const flow of autoApplyFlows) {
try {
@ -538,8 +560,35 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
throw error;
}
}
return results;
};
// 如果不使用缓存,直接执行
if (!cacheKey || !this.flowEngine) {
return await executeAutoFlows();
}
// 使用缓存机制
const promise = executeAutoFlows()
.then((result) => {
this.flowEngine.applyFlowCache.set(cacheKey, {
status: 'resolved',
data: result,
promise: Promise.resolve(result),
});
return result;
})
.catch((err) => {
this.flowEngine.applyFlowCache.set(cacheKey, {
status: 'rejected',
error: err,
promise: Promise.reject(err),
});
throw err;
});
this.flowEngine.applyFlowCache.set(cacheKey, { status: 'pending', promise });
return await promise;
}
/**