xi-hub
← 全部作品

2026 · 在线 · 主设计 + 核心实现

Xi Flow

面向长流程任务的节点式编排引擎,把「一堆异步脚本」变成可视化、可回放、可断点恢复的工作流。

首屏 JS
-38%
节点调度延迟
从 120ms → 24ms
单测覆盖率
87%
技术栈
  • TypeScript
  • React
  • XState
  • Vite
  • Web Worker
关键词
  • 架构
  • 状态机
  • 可视化

问题

团队里的自动化任务散落在十几个 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 脚本迁移了进来,排障时间从「翻半天日志」变成「拖一下时间轴」。

复盘

最大的坑是过度设计:第一版做了完整的插件系统,结果一个插件都没人写。 第二版砍掉插件层,只保留节点协议,反而被真正用起来了。