这是一篇关于协作文本编辑的博客文章,主要介绍了一种无需使用冲突复制数据类型(CRDT)或操作转换(OT)的协作文本编辑方法,以及相关的技术细节和实现思路。
- 核心问题:在协作文本编辑中,当多个用户同时编辑文本时,如何将用户的操作发送到服务器,并让服务器以“明显”正确的方式更新其自身的文本。这就是所谓的“索引重新定位”挑战,不仅影响实时协作应用,也会影响非实时应用。
- 现有解决方案的问题:现有的解决方案分为 CRDT 和 OT 两类。CRDT 为每个字符分配一个不可变的 ID,并使用数学全序对这些 ID 进行排序;OT 则直接“转换”操作以考虑并发编辑。然而,这两种方法都存在概念复杂性高、实现困难等问题,而且使用它们的库通常是全栈的,难以定制,当应用需要一些库作者未预料到的功能时,就会成为负担。
提出的方法:
- 主要思想:为每个文本字符标记一个全局唯一的 ID,客户端向服务器发送“在……之后插入”操作,服务器按字面意思解释这些操作,即在目标 ID 之后插入新字符。
- 一些修正:客户端在发送操作时还需要指定新元素的 ID,并且服务器在处理操作时需要考虑字符被删除的情况。
- 客户端方面:通过服务器协调(server reconciliation)来实现乐观本地更新,即客户端在收到服务器的新远程操作之前,先撤销所有挂起的本地操作,然后应用远程操作,最后重新执行仍挂起的本地操作。还有一种更简单的策略是禁止客户端在拥有挂起的本地操作时处理远程操作,但这种策略可能会导致无限延迟。
- 与 CRDT 的区别:该方法以直接灵活的方式处理顺序,客户端告诉服务器在某个 ID 之后插入 X,服务器就会执行相应操作,而无需像文本编辑 CRDT 那样使用复杂的算法来排序 ID。
讨论:
- 并发插入:当多个用户同时在同一位置插入文本时,服务器会按照收到操作的相反顺序处理这些操作,最终的文本顺序与服务器收到操作的顺序相反。
- 灵活操作:该方法支持多种文本编辑操作,服务器可以根据客户端的操作进行灵活处理,而 CRDT 和 OT 算法只允许满足严格代数规则的操作。例如,服务器可以对并发插入的文本进行更智能的处理,或者支持“插入之前”、“修复拼写错误”等操作。
- 富文本(格式化):在处理富文本时,将格式化范围转换为字符 ID,服务器可以根据这些 ID 对文本进行格式化处理。
- 去中心化变体:如果应用没有中央服务器或服务器可选,可以使用去中心化的方式为操作分配最终的全序,例如使用 Lamport 时间戳。这种算法是一种文本编辑 CRDT,其行为与一些现有的文本编辑 CRDT 类似。
- 辅助库:Articulated:这是一个用于帮助实现上述方法的 npm 库,它提供了一个优化的
IdList
数据结构,用于管理字符 ID 列表,提高了操作效率,并具有持久化功能,便于服务器协调。
总之,这种无需使用 CRDT 或 OT 的协作文本编辑方法简单灵活,能够满足多种协作文本编辑的需求,并且可以通过辅助库进一步优化和扩展。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。