← 全部作品
2026 · 在线 · 主设计 + 核心实现
Xi Flow
面向长流程任务的节点式编排引擎,把「一堆异步脚本」变成可视化、可回放、可断点恢复的工作流。
- 首屏 JS
- -38%
- 节点调度延迟
- 从 120ms → 24ms
- 单测覆盖率
- 87%
问题
团队里的自动化任务散落在十几个 cron 脚本里:没有重试、没有状态、出错只能翻日志。 我想把它们收敛成一个可以被看见的系统——不只是跑起来,还要知道跑到哪一步、卡在哪、能不能从断点继续。
我的角色
从状态机建模到编辑器交互的全链路设计,以及核心调度器的实现。
约束
- 不能引入后端,纯前端要能独立跑通
- 单个流程节点数上限 500,编辑器必须保持 60fps
- 已有脚本要能低成本迁移
方案
调度层用 XState 建模,每个节点是一个独立的 actor,生命周期与 UI 完全解耦。 渲染层做了三层分离:
- 静态层:连线与网格用 SVG,一次性绘制,不参与每帧重排
- 动态层:拖拽中的节点走单独的 canvas,避免触发 React 重渲染
- 回放层:执行记录存成事件流,随时可以拖时间轴重演
// 断点恢复的关键:把节点状态序列化成可重放的事件
const snapshot = machine.getPersistedSnapshot();
await store.put(flowId, { snapshot, cursor });
关键决策
为什么不用现成的流程图库:它们大多把「图」当成 DOM 来管,节点一多就掉帧。 我把图当成数据,DOM 只是投影,拖拽期间直接操作 canvas,结束才回写状态。
为什么调度放 Web Worker:500 个节点的拓扑排序在主线程会阻塞 200ms 以上, 放进 Worker 后主线程只负责渲染。
一个经验:先让数据结构正确,再谈交互。反过来的顺序我试过,代价是重写两遍。
结果
编辑器在 500 节点规模下拖拽稳定 60fps,首屏 JS 减少 38%, 团队把 14 个 cron 脚本迁移了进来,排障时间从「翻半天日志」变成「拖一下时间轴」。
复盘
最大的坑是过度设计:第一版做了完整的插件系统,结果一个插件都没人写。 第二版砍掉插件层,只保留节点协议,反而被真正用起来了。