跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

WebSocket实现多人在线协作文档 实时编辑前端冲突处理【实战】

前端必须实现操作队列、版本校验与本地暂存,配合服务端OT/CRDT协同,否则多人编辑必丢数据或覆盖错误——WebSocket只传不管对错。 前端不做冲突处理,就一定会丢数据或覆盖错内容——WebSocket只管传,不管对错。 为什么直接用
onmessage
覆盖全文会出问题 很多快速实现方案(比如 Flask + Vue 简单广播)让每个编辑操作都把整个文档内容发过来,前端收到就
editor.setValue(newContent)
。这在单人编辑时没问题,但两人同时改:A删了第3行,B在第2行末尾加了字,谁后到谁赢,先到的操作被彻底抹掉。 浏览器没有“操作队列”概念,
setValue
是原子覆盖,不保留任何上下文 网络延迟导致消息乱序,后发的操作可能先到,前端无法判断该不该应用 用户本地光标位置、选区状态全丢,强行覆盖后体验断裂
insertText
和
deleteText
必须带位置与版本校验 真正可落地的前端同步,得把“用户做了什么”拆成最小可逆操作,并附带执行前提。不能只传结果,要传动作 + 上下文。 服务端推送的消息必须含
op
字段,如
{"type":"insert","index":42,"text":"OK","version":12}
或
{"type":"delete","index":42,"length":2,"version":12}
前端收到后,先比对本地
version
:若
msg.version <= localVersion
,直接丢弃(已过期);若 >,再检查
index
是否仍在有效范围内(防因前面操作导致偏移错位) 编辑器需支持底层操作调用,比如 CodeMirror 6 的
view.dispatch()
,Monaco 的
executeEdits()
,而不是走
setValue()
这种高层封装 前端必须维护本地操作暂存与回滚能力 用户正在输入时 WebSocket 断连,重连后不能只靠服务端补发——那些未发出的本地操作必须还在,且能和补发操作合并重放。 面向设计的AXUI前端框架表单 面向设计的AXUI前端框架表单是一款包含表格、列表、弹窗等的AXUI前端框架表单下载。 下载 立即学习 “ 前端免费学习笔记(深入) ”; 每次键盘输入触发的操作,先存进一个
pendingOps
队列,同时打上本地时间戳和随机
clientId
连接断开时,暂停发送,但允许用户继续编辑;重连后,先发
{"type":"sync:pending","ops":pendingOps}
给服务端做 OT 合并,再接收服务端返回的权威状态 服务端返回的同步消息里如果含
rebase:true
,说明你的本地操作已被转换,前端要按新
index
重算并应用,不能硬套原位置 光靠前端永远不够:必须和服务端 OT/CRDT 协同 前端所有“校验”“暂存”“重算”都只是防御性措施,最终一致性锚点永远在服务端。你看到的
version
、
rebase
、
clientId
全是服务端生成和裁定的。 不要自己实现 OT 变换函数——Java 后端用
sharedb
或
ottypes
,Node.js 用
ot-json0
,它们输出的
op
结构前端才能安全消费 前端收到的每条消息,都应有服务端签发的
serverTimestamp
,用于和本地操作排序,而非依赖
Date.now()
最易忽略的一点:前端必须监听
beforeunload
,把未提交的
pendingOps
存 localStorage,否则刷新页面就真丢了

相关文章