项目结项报告

tianyi Lv3

TinyEngine低代码引擎支持多人协作能力 项目结项报告

项目信息

  • 项目名称: TinyEngine低代码引擎支持多人协作能力 https://summer-ospp.ac.cn/org/prodetail/2536e0204?list=org&navpage=org
  • 项目方案描述:
    • 通过 CRDT 无冲突复制数据类型(Yjs)完成对低代码 Schema 及其 UI 的协同编辑操作并解决操作冲突问题;
    • 通过 Yjs Awarenss 完成 多人协作时的消息通知和在线用户展;
    • 新增 版本管理 (version-control)Plugin 界面,并搭建 branch-commit 系统,为低代码引擎提供版本管理能力;
  • 时间规划
    • 7.1 - 7.12 构思大致方案
    • 7.15 - 7.25 完成版本管理界面的静态页面
    • 7.25 - 8.15 搭建完成版本管理功能,并进行前后端联调
    • 8.16 - 8.20 重构版本管理界面,修复版本管理功能bug
    • 8.21- 8.30 构思 低代码引擎 多人协作的实现思路,搭建 Yjs 基建,为多人协同系统提供基础能力
    • 9.1 - 9.20 实现 低代码引擎 的物料多人拖拽功能;实现低代码引擎 Schema 的属性,样式,高级设定和事件方法的协同编辑同步,实现显示用户在线功能,实现他人远端框选,本地显示的消息通知功能
    • 9.21 - 9.30 修复多人协作功能 bug,完善文档 readme

项目进度

已完成工作

版本管理 界面 Plugin

  • 搭建 功能完整,界面美观的版本管理界面
  • 实现展示各个分支 各个 commit的提交内容
  • 实现针对 commit 的 关于作者,commit hash,时间,标签的索引功能
  • 实现新建分支,新建标签,提交(新建)commit的各项功能
  • 实现从各个 commit 创建新提交的功能,提供版本回退功能
  • 实现查看 commit diff 的功能

低代码多人协同功能

  • 实现 多人拖拽物料 同步
  • 实现 协作编辑消息通知 功能,包括鼠标同步,展示其他用户正在何处编辑的功能
  • 实现 显示在线用户功能,包括用户进入与离开的消息通知
  • 实现 低代码多人同步编辑:样式,属性,高级特性,事件绑定的功能
  • 通过 CRDT 无冲突复制数据类型的最终一致性和免去手动冲突解决,解决多人编辑的数据冲突问题

遇到的问题及解决方案

Yjs 协同开发总结

使用了 Yjs。在这个过程中遇到了不少问题,也积累了一些经验。下面是我的总结。

问题一:meta 数据无法在远端传递

一开始我尝试在 transaction.meta 中记录操作意图,比如标记某个操作是“移动节点”,而不是单纯的几次插入和删除。本地调试时数据都在,但当操作通过 WebSocket 传到远端时,transaction.meta 始终是空的。

后来查资料才知道,Yjs 的 meta 数据并不会通过网络传输,它的作用仅限于在同一个客户端内部的监听器之间传递信息。跨客户端的“操作意图”必须通过其他方式来传递。

解决方法:事件总线

为了解决这个问题,我在 Y.Doc 中单独建了一个 Y.Map,作为“事件总线”。

  • 发起操作时,不仅修改真实的数据结构,还在事件总线中写入一条事件。
  • 其他客户端通过监听这个事件总线,就能感知到操作意图。

这样,状态变更和操作意图分离,逻辑更清晰,也更符合 Yjs 的机制。

问题二:性能与 UI 闪烁

当用户掉线后重连,一次性同步过来很多操作时,事件监听器会被频繁触发,每次都调用 applyPatches 更新 UI,导致页面卡顿和闪烁。

解决方法:批量处理

改进后的做法是:

  1. 在监听器中只记录需要的变更,不直接操作 UI。
  2. 使用 Yjs 的 'afterTransaction' 钩子,在整个事务完成后,再统一处理并调用 applyPatches
  3. 前端框架会自动优化批量状态变更,最终只触发一次重绘。

这样性能问题和闪烁现象就解决了。

一些额外的话

  1. 软删除优于硬删除:直接删除节点可能在并发场景下产生问题,软删除(打标记)能保证数据一致性和可恢复性。
  2. 事件需及时清理:事件总线中的事件在被消费后必须立即删除,否则新客户端加入时会重复处理旧事件,导致错

Yjs 协同实践中的设计模式总结

在低代码平台的协同开发中,最初只是围绕 Bug 去解决问题。但随着逐步深入,我发现自己在无意识中,其实已经应用了多种经典的设计模式。这些模式为架构清晰度、扩展性和稳定性提供了很大帮助。以下是我的总结。

1. 命令模式(Command Pattern)

命令模式的核心是把一次操作封装成一个独立对象,既包含操作意图,也包含执行所需的上下文。

在项目中的应用

  • 当用户执行某个操作(如删除节点),我会生成一个命令对象,例如 { op: 'delete', nodeId: 'abc' }
  • 该对象被写入事件总线(__app_events__),再由远端的监听器统一消费并执行。

作用与价值

  • 发起者和执行者解耦,UI 层不需要知道底层执行逻辑。
  • 新增操作类型时,只需增加新的命令对象和对应的处理逻辑,不会影响已有代码。

2. 观察者模式(Observer Pattern)

观察者模式用于在数据变化时,自动通知所有订阅者。

在项目中的应用

  • Y.Doc 及其内部的 Y.MapY.Array 充当“主题”。
  • 各类监听器函数是“观察者”。
  • 当远端用户修改了数据,本地监听器会自动收到通知。

作用与价值

  • 从“主动轮询”转变为“被动响应”,让系统天然具备响应式特性。
  • 需要注意的是,观察者不宜承担过多逻辑,应只负责“信号传递”,重任务应交给后续批处理流程。

3. 策略模式(Strategy Pattern,雏形)

策略模式强调将不同算法独立封装,按需选择。

在项目中的应用

  • applyPatches 中使用 switch 根据 patch.type 选择不同逻辑,类似于在运行时挑选策略。
  • 例如:array-insertarray-deletearray-swap 对应不同的处理方式。

改进空间

  • 可以将每个分支逻辑独立封装成策略函数或类,并用一个映射表维护,进一步提升可扩展性和可维护性。

测试报告

关于 版本管理界面 各个组件的测试

测试内容包括:渲染左侧标题与文档链接,渲染分支下拉列表并正确显示 all 与可用分支,搜索框输入触发 search 事件,选择分支触发 branch-change 和 update:currentBranch,点击“标签”和“分支”按钮分别触发 createTag 与 createBranch,以及点击关闭按钮触发 close。测试覆盖了渲染、异步数据加载、用户交互和事件触发等关键逻辑,保证组件在显示和交互上符合预期行为,能够正确通知父组件状态变化。
结果:alt text

关于 多人协作系统 的测试

实时同步

  • 创建与加入:一个用户创建内容(如文档、白板、设计稿),其他用户能否实时看到新创建的内容?一个用户加入协作会话,能否立即加载并看到最新的、完整的内容?
  • 内容操作同步:文本编辑: 用户A输入、删除、修改文本,用户B、C的屏幕上是否逐字或近实时地同步变化?
  • 对象操作: 用户A移动、缩放、旋转、删除一个图形/组件,其他用户是否能实时看到平滑的动画或最终结果?
  • 属性修改: 用户A更改颜色、字体、边框等属性,其他用户是否能立即看到变化?
  • 状态同步:光标/指针位置: 用户A移动鼠标,其他用户能否实时看到代表A的指针/光标在屏幕上移动?
  • 选中状态: 用户A选中一个或多个对象,其他用户能否看到这些对象被高亮或出现选中框,并显示是A选中的?
    结果: alt text

后续工作安排

项目虽然完成,但自己觉得仍有许多需要改进完善修复的地方

  • 完善 版本管理 系统,修复已有问题,视情况提供更多版本操作的功能
  • 视情况实现 Monaco 同步编辑功能,因为这部分代码耦合度过高,难以在原来的基础上添加新的功能,可能需要重写大部分逻辑
  • 视情况丰富用户在进行协同编辑时的 交互体验
  • Title: 项目结项报告
  • Author: tianyi
  • Created at : 2025-10-02 11:44:32
  • Updated at : 2025-10-08 15:42:17
  • Link: https://github.com/ztygod/2025/10/02/项目结项报告/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments