网页白板笔迹实时同步的核心是用websocket传输可合并的增量操作指令,服务端轻量协调、客户端乐观渲染,通过笔迹id建模、本地聚合广播与最终一致性实现高效协同。

网页白板的笔迹实时同步核心在于:用 WebSocket 传输最小化、可合并的增量操作,而非整幅画布或全量坐标点。关键不是“传得快”,而是“传得准、合得对、不冲突、不丢笔”。
一、笔迹建模为可序列化的操作指令
把每次鼠标/触控动作抽象为带时间戳和上下文的操作对象,避免直接传原始 canvas 像素或大数组:
- start:{ type: "pen", id: "p123", x, y, color, size, ts } —— 笔迹起点,含唯一笔迹 ID(客户端生成 UUID)
- move:{ type: "move", id: "p123", x, y, ts } —— 追加点,只传相对变化或绝对坐标均可,推荐绝对坐标(防累积误差)
- end:{ type: "end", id: "p123", ts } —— 标记该笔迹完成,服务端可触发归档或广播收尾事件
- 支持撤销粒度:每条笔迹(id)即一个可撤回单元;不建议按单个 move 点撤销
二、服务端做轻量状态协调与冲突消解
WebSocket 服务端不存储完整画布,只维护“活跃笔迹 ID 集合”和“最近 N 秒内操作缓冲区”,用于应对网络抖动和乱序:
- 收到 move 消息时,检查 id 是否已存在且未 end;若已 end,则丢弃或转为新笔迹(防重放)
- 按 clientID + timestamp 做简单去重(同客户端 50ms 内重复 move 自动过滤)
- 不强制全局顺序:允许不同笔迹并行广播;同一笔迹内 move 必须按 ts 保序,服务端可缓存乱序 move 并等待前序点到达后批量转发
- 不实现 OT 或 CRDT——白板笔迹天然具备“追加写”特性,无字段编辑冲突,无需复杂协同算法
三、客户端本地聚合 + 差分广播策略
减少频次、提升抗抖动能力,不每动一下就发一次 WebSocket 消息:
- 启用 requestAnimationFrame 节流:每 16–33ms 采集一次位移,合并为 1~3 个 move 指令再发送
- 长线优化:连续 move 距离小且角度变化平缓时,用贝塞尔控制点压缩(如传起点、终点、1 个中点),服务端不做解析,仅透传,由各客户端渲染时插值
- 断线重连后,不拉全量历史——改用“同步最后 10 秒活跃笔迹 ID 列表 + 各自补全未 end 的笔迹”机制,大幅降低重连开销
四、渲染层保持最终一致性,不依赖服务端画布
所有客户端独立绘制,服务端只做消息中继与基础校验:
- canvas 渲染完全在前端:收到 start → 创建路径;move → lineTo;end → stroke 并缓存该笔迹为不可变对象
- 不依赖服务端返回的“确认帧”来渲染——延迟敏感操作必须“乐观渲染”:本地立即画,出错(如 id 冲突)再局部回滚
- 为支持回放/导出,客户端本地记录完整操作日志(localStorage 或 IndexedDB),格式与 WebSocket 消息一致,便于复用
本质上,这不是一个需要强一致算法的问题,而是一个合理划分职责的问题:客户端负责采集、聚合、渲染;服务端负责去重、保序、广播;协议设计聚焦于可扩展性与容错性,而非理论完备性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











