知识点思维导图
17 个知识节点
参考资料
富文本编辑器(08) - Yjs 协同编辑
读完后,你应能完成以下任务:
- 绘制“富文本编辑器(08) - Yjs 协同编辑 / 前言”的关键对象与数据流,解释“在多人协作的编辑场景中,如何保证文档的一致性是一个复杂的技术问题。”,并用源码位置、日志或 Trace 标注证据。
- 为“富文本编辑器(08) - Yjs 协同编辑 / OT 算法”设计正常与异常输入,验证“用户 A 发送操作: insert("x", 1) -> 用户 B 发送操作: insert("y", 2)”,输出首个偏差位置与回归测试结果。
- 实现“富文本编辑器(08) - Yjs 协同编辑 / 什么是 OT 算法”的最小代码或配置,检验“OT(Operational Transformation)是一种用于协同编辑的算法,它通过转换操作来解决冲突,确保所有用户看到相同的最终结果。”,输出命令、结果与 Diff,并说明不适用边界。
一、前言
在多人协作的编辑场景中,如何保证文档的一致性是一个复杂的技术问题。当多个用户同时编辑同一个文档时,需要解决冲突、保持同步,并确保最终结果的一致性。目前主要有两种算法来解决这个问题:OT(Operational Transformation) 和 CRDT(Conflict-free Replicated Data Types)。
二、OT 算法
2.1 什么是 OT 算法
OT(Operational Transformation)是一种用于协同编辑的算法,它通过转换操作来解决冲突,确保所有用户看到相同的最终结果。
2.2 工作原理
假设我们有一个文档,内容是 "abc",两个用户同时编辑:
初始状态: "abc"
用户 A 的操作: 在位置 1 插入 "x" → "axbc"
用户 B 的操作: 在位置 2 插入 "y" → "abyc"
如果没有 OT 算法,直接应用操作会导致冲突:
- 用户 A 看到:
"axbc" - 用户 B 看到:
"abyc"
2.3 OT 算法解决冲突
OT 算法的核心思想是转换操作,让操作能够适应其他用户的操作:
- 用户 A 发送操作:
insert("x", 1) - 用户 B 发送操作:
insert("y", 2) - 服务器转换操作:
- 用户 A 收到:
insert("x", 1)+ 转换后的insert("y", 3)→"axbyc" - 用户 B 收到:
insert("y", 2)+ 转换后的insert("x", 1)→"axbyc"
- 用户 A 收到:
最终结果: 两个用户都看到 "axbyc"
2.4 OT 算法的特点
- ✅ 实时性好:操作立即生效
- ✅ 冲突解决:通过转换操作解决冲突
- ❌ 复杂度高:转换规则复杂,难以实现
- ❌ 中心化:需要中央服务器协调
可视化的展示 OT 算法的执行和流转过程 https://operational-transformation.github.io/index.html
三、CRDT 算法
3.1 什么是 CRDT 算法
CRDT(Conflict-free Replicated Data Types)是一种无冲突的复制数据类型,它通过设计数据结构本身来避免冲突,而不需要转换操作。
3.2 工作原理
同样以文档 "abc" 为例,两个用户同时编辑:
初始状态: "abc"
用户 A 的操作: 在位置 1 插入 "x"
用户 B 的操作: 在位置 2 插入 "y"
3.3 CRDT 算法解决冲突
CRDT 通过给每个字符分配唯一标识符来避免冲突。下面是简单方便理解的例子,具体 CRDT 更复杂:
初始状态: "abc"
"a"的标识符:(0, 'A')"b"的标识符:(1, 'A')"c"的标识符:(2, 'A')
用户 A 在位置 1 插入 "x":
- 新字符
"x"的标识符:(0.5, 'A')(在 0 和 1 之间) - 结果:
"axbc"
用户 B 在位置 2 插入 "y":
- 新字符
"y"的标识符:(1.5, 'B')(在 1 和 2 之间) - 结果:
"abyc"
合并时按标识符排序:
(0, 'A')→"a"(0.5, 'A')→"x"(1, 'A')→"b"(1.5, 'B')→"y"(2, 'A')→"c"
最终结果: "axbyc"
3.4 CRDT 算法的特点
- ✅ 去中心化:不需要中央服务器
- ✅ 简单可靠:算法相对简单,不容易出错
- ✅ 最终一致性:保证最终结果一致
- ❌ 存储开销:需要存储额外的元数据
- ❌ 延迟较高:需要等待所有操作到达
四、Yjs 中的实现
4.1 Yjs 简介
Yjs 是一个基于 CRDT 的协同编辑库
4.2 在 TipTap 中集成 Yjs
Yjs 点过来跳转到了Tiptap,也就是这里: https://tiptap.dev/docs/collaboration/getting-started/install
当然也可以直接看这个Demo:https://tiptap.dev/docs/examples/advanced/collaborative-editing,这是官方提供的商业服务 tiptap cloud
注意用 tiptap cloud 7天没有使用需要在 https://cloud.tiptap.dev/v1/apps/settings 恢复应用,注意只有 30 天试用期
也有免费的,应该是大部分的人的选择,也就是 Hocuspocus ✅
启动后端服务
下面是最简单的,但是我们往往需要自己部署后端服务,可以参考 https://tiptap.dev/docs/hocuspocus/server/examples
npx @hocuspocus/cli
前端 tiptap 接入文档 https://tiptap.dev/docs/hocuspocus/provider/examples#tiptap
'use client'
import './styles.scss'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { EditorContent, useEditor } from '@tiptap/react'
import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'
// Importing the provider and useEffect
import { useEffect } from 'react'
import { HocuspocusProvider } from '@hocuspocus/provider'
const ydoc = new Y.Doc()
export default function Page() {
const editor = useEditor({
immediatelyRender: false,
extensions: [
Document,
Paragraph,
Text,
Collaboration.configure({
document: ydoc
})
],
content: `
<p>
This is a radically reduced version of Tiptap. It has support for a document, with paragraphs and text. That’s it. It’s probably too much for real minimalists though.
</p>
<p>
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
</p>
`
})
// Connect to your Collaboration server
useEffect(() => {
const provider = new HocuspocusProvider({
url: 'ws://127.0.0.1:1234',
name: 'example-document',
document: ydoc
})
}, [])
return <EditorContent editor={editor} />
}
4.3 实时同步流程
- 用户输入 → TipTap 编辑器
- 生成操作 → Yjs 处理
- 网络传输 → WebSocket/WebRTC
- 接收操作 → 其他客户端
- 应用操作 → 更新编辑器
五、总结
- 前言:在多人协作的编辑场景中,如何保证文档的一致性是一个复杂的技术问题。
- CRDT 算法:CRDT(Conflict-free Replicated Data Types)是一种无冲突的复制数据类型,它通过设计数据结构本身来避免冲突,而不需要转换操作。
- Yjs 中的实现:用户输入 → TipTap 编辑器 -> 生成操作 → Yjs 处理 -> 网络传输 → WebSocket/WebRTC -> 接收操作 → 其他客户端
- 什么是 OT 算法:OT(Operational Transformation)是一种用于协同编辑的算法,它通过转换操作来解决冲突,确保所有用户看到相同的最终结果。
- OT 算法的特点:✅ 冲突解决:通过转换操作解决冲突
- CRDT 算法解决冲突:CRDT 通过给每个字符分配唯一标识符来避免冲突。
学完自测
选择所有正确答案;提交后逐项核对判断依据。