Skip to content

协同编辑基本原理

DocCollab的核心功能是支持多用户实时协同编辑文档。这一功能主要基于CRDT (Conflict-free Replicated Data Type) 算法和Yjs库实现。

CRDT算法简介

CRDT是一种特殊的数据结构,它允许多个用户在不需要中央协调的情况下同时编辑共享数据,同时保证最终一致性。

CRDT的主要特点:

  • 无冲突:CRDT设计用于自动解决冲突,不需要人工干预
  • 最终一致性:所有用户的编辑操作最终会收敛到相同的状态
  • 分布式:不需要中央服务器来解决冲突,适合离线编辑场景
  • 可扩展:可以支持大量用户同时编辑

Yjs技术栈

Yjs 是一个高性能的CRDT实现库,DocCollab使用它作为协同编辑的基础:

┌─────────────────┐
│     Slate.js    │  ◀── 编辑器框架
└────────┬────────┘

┌────────┴────────┐
│   @slate-yjs    │  ◀── Slate与Yjs的绑定库
└────────┬────────┘

┌────────┴────────┐
│      Yjs        │  ◀── CRDT实现
└────────┬────────┘

┌────────┴────────┐
│  WebSocket/WebRTC │  ◀── 网络传输
└─────────────────┘

系统工作流程

  1. 本地编辑处理

    • 用户在Slate编辑器中输入内容
    • 编辑操作被转换为Yjs操作
    • 操作应用到本地文档模型
  2. 更新同步

    • 本地操作通过WebSocket发送到服务器
    • 服务器将操作广播给所有连接的客户端
    • 其他客户端接收操作并应用到自己的本地文档
  3. 冲突解决

    • 当多个用户同时编辑同一区域时,Yjs自动解决冲突
    • 应用特定的合并策略确保所有用户最终看到相同的内容
  4. 光标同步

    • 用户光标位置作为元数据随文档更新一起传输
    • 每个客户端在屏幕上显示其他用户的光标位置
    • 每个用户的光标使用不同颜色区分

协同编辑示例

以下是协同编辑的简化代码示例:

jsx
// 创建协同编辑器
const { editor, isConnected, remoteUsers } = useCollaborativeEditor(documentId);

// 编辑器组件
<Slate editor={editor} value={value} onChange={setValue}>
  <Toolbar />
  <CursorOverlay> {/* 显示其他用户的光标 */}
    <Editable
      renderElement={renderElement}
      renderLeaf={renderLeaf}
      // ...其他属性
    />
  </CursorOverlay>
</Slate>

// 显示在线用户
<UserAvatars users={remoteUsers} />

服务器配置

DocCollab使用Hocuspocus作为协同编辑的WebSocket服务器:

javascript
// server.js
import { Server } from '@hocuspocus/server';
import { Database } from '@hocuspocus/extension-database';

// 创建Hocuspocus服务器实例
const server = Server.configure({
  port: 1234,
  extensions: [
    new Database({
      // 持久化文档数据
      fetch: async ({ documentName }) => {/* 从数据库获取文档 */},
      store: async ({ documentName, state }) => {/* 保存文档到数据库 */}
    }),
  ],
});

// 启动服务器
server.listen();

Released under the MIT License.