OT vs CRDT:前端开发者的协同编辑技术选择
作为前端开发者,当我们需要实现类似 Google Docs 的协同编辑功能时,主要有两种技术方案:OT(操作转换) 和 CRDT(无冲突复制数据类型)。本文将从实际开发角度对比这两种方案。
快速理解两种方案
OT(操作转换)- 传统方案
想象两个人同时在文档的同一位置插入文字,OT 需要”协调”这些操作:
// 用户A在位置5插入"Hello"
// 用户B同时在位置5插入"World"
// OT需要转换:谁的操作先执行?位置如何调整?CRDT(无冲突复制数据类型)- 现代方案
每个操作都有唯一标识,自动合并,无需协调:
// 每个操作都有全局唯一ID,自动排序合并
// 不需要复杂的转换逻辑从开发体验对比
OT 的开发痛点
1. 复杂的转换逻辑
// OT需要为每种操作组合写转换函数
function transformInsertInsert(op1, op2) {
if (op1.position <= op2.position) {
return [op1, { ...op2, position: op2.position + op1.length }]
} else {
return [{ ...op1, position: op1.position + op2.length }, op2]
}
}
function transformInsertDelete(op1, op2) {
// 又是一堆复杂逻辑...
}
function transformDeleteDelete(op1, op2) {
// 更多复杂逻辑...
}
// 还有很多很多组合...2. 难以调试
// OT的bug很难追踪
// 操作A + 操作B = 正常
// 操作B + 操作A = 出错?
// 需要检查所有转换函数的组合CRDT 的开发优势
1. 简洁的实现
// 使用Yjs,几行代码搞定协同编辑
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
const ydoc = new Y.Doc()
const ytext = ydoc.getText('content')
const provider = new WebsocketProvider('ws://localhost:1234', 'room', ydoc)
// 插入文本
ytext.insert(0, 'Hello World')
// 就这么简单!2. 与前端框架完美集成
// React + TipTap + Yjs
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Collaboration from '@tiptap/extension-collaboration'
function CollaborativeEditor() {
const editor = useEditor({
extensions: [
StarterKit,
Collaboration.configure({
document: ydoc, // 直接传入Yjs文档
}),
],
})
return <EditorContent editor={editor} />
}实际项目中的差异
网络处理
OT 的网络问题
// OT需要保证操作顺序,网络延迟会影响体验
class OTEditor {
sendOperation(op) {
// 必须等待服务器确认才能继续
this.waitingForAck = true
this.socket.send(op)
}
onAck() {
this.waitingForAck = false
// 处理缓存的操作...
}
}CRDT 的网络优势
// CRDT可以立即应用操作,后台同步
class CRDTEditor {
insert(pos, text) {
// 立即在本地显示
this.ytext.insert(pos, text)
// 自动同步到其他客户端,无需等待
}
}离线支持
OT 的离线困难
// OT离线后重连很复杂
class OTEditor {
goOffline() {
// 需要缓存所有操作
this.offlineOps = []
}
goOnline() {
// 重连时需要重新计算所有转换
this.resyncAllOperations()
}
}CRDT 的离线友好
// CRDT天然支持离线
import { IndexeddbPersistence } from 'y-indexeddb'
// 自动本地存储
const persistence = new IndexeddbPersistence('doc-id', ydoc)
// 离线编辑,上线自动同步
// 无需额外代码!性能对比(前端关心的指标)
| 指标 | OT | CRDT |
|---|---|---|
| 首次加载 | 快 | 稍慢(需要加载更多元数据) |
| 编辑响应 | 慢(需要等待转换) | 快(立即响应) |
| 内存占用 | 低 | 中等 |
| 包大小 | 大(复杂逻辑) | 小(Yjs ~100KB) |
| 开发难度 | 极高 | 低 |
实际项目选择建议
选择 CRDT 的场景(推荐)
// 适合大部分前端项目
const shouldUseCRDT = {
richTextEditor: true, // 富文本编辑器
codeEditor: true, // 代码协同编辑
drawingApp: true, // 绘图应用
mobileApp: true, // 移动端应用
offlineFirst: true, // 需要离线支持
rapidDevelopment: true // 快速开发
}选择 OT 的场景(少数)
// 只在特殊情况下考虑
const shouldUseOT = {
extremeBandwidthLimit: true, // 极端带宽限制
simpleTextOnly: true, // 只有纯文本
legacySystem: true // 已有OT系统
}现代前端生态系统
CRDT 生态(推荐)
// 丰富的前端工具链
import * as Y from 'yjs' // 核心库
import { WebsocketProvider } from 'y-websocket' // WebSocket同步
import { IndexeddbPersistence } from 'y-indexeddb' // 本地存储
import { TiptapCollabExtension } from '@tiptap/extension-collaboration' // TipTap集成
// Vue集成
import { VueEditor } from '@tiptap/vue-3'
// React集成
import { useEditor } from '@tiptap/react'实际项目示例
// 一个完整的协同编辑器组件
import React, { useEffect } from 'react'
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Collaboration from '@tiptap/extension-collaboration'
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
export default function CollaborativeEditor({ roomId, userName }) {
const ydoc = new Y.Doc()
const editor = useEditor({
extensions: [
StarterKit.configure({ history: false }),
Collaboration.configure({ document: ydoc }),
CollaborationCursor.configure({
provider: new WebsocketProvider('ws://localhost:1234', roomId, ydoc),
user: { name: userName, color: '#f783ac' },
}),
],
})
return <EditorContent editor={editor} />
}
// 就这么简单,一个协同编辑器就完成了!为什么前端开发者更喜欢 CRDT?
1. 开发效率
- OT: 需要几个月实现和调试
- CRDT: 几天就能上线
2. 用户体验
- OT: 操作有延迟,需要等待服务器
- CRDT: 立即响应,感觉像本地编辑
3. 维护成本
- OT: 复杂的bug,难以修复
- CRDT: 简单直观,易于维护
4. 现代化特性
// CRDT支持现代前端需求
const modernFeatures = {
offlineFirst: '✅ 天然支持',
mobileOptimized: '✅ 移动端友好',
frameworkAgnostic: '✅ 框架无关',
typescript: '✅ 完整类型支持',
ssr: '✅ 服务端渲染支持'
}总结
作为前端开发者,强烈推荐选择 CRDT 方案:
- 学习成本低 - 几小时就能上手
- 开发速度快 - 几天就能实现协同功能
- 用户体验好 - 真正的实时协同
- 维护简单 - 不用担心复杂的转换逻辑
- 生态完善 - 与主流前端框架完美集成
除非你的项目有极特殊的限制(比如极端的带宽要求),否则 CRDT 就是最佳选择。现代协同编辑应用如 Notion、Figma 等都在使用 CRDT 相关技术,这已经成为行业标准。
一句话总结:选择 CRDT,让协同编辑变得简单!
Last updated on