您现在的位置是:亿华云 > 热点

对前端来说开发一个在线文档需要啥技术?

亿华云2025-10-02 19:05:58【热点】5人已围观

简介前言开发一个在线文档我们可能要解决的问题:最基础的文本编辑功能(哦?好像textarea就可以完成,那如果是富文本呢?)我们需要一个文档模型来描述文档;富文本编辑器,提供富文本的编辑和渲染能力;协同功

前言

开发一个在线文档我们可能要解决的对前端说问题:

最基础的文本编辑功能(哦?好像textarea就可以完成,那如果是个线富文本呢?)我们需要一个文档模型来描述文档;富文本编辑器,提供富文本的文档编辑和渲染能力;协同功能,不同的需啥用户对同一份文档的编辑需要保持大家看到的都是一样的;协同网络模型,保证服务器和客户端之间的技术文档模型一致;

名词解释

OT:一种解决协同问题的算法;

OP:operation的简称,在OT中指的对前端说是一次操作;

etherpad: 一个实现文档协同功能的开源库;

easysync: etherpad中实现文档协同的核心算法,是个线OT算法的一种,主要用来处理文本协同;

ot-json:ot算法的文档一种,顾名思义,需啥是技术主要用来处理结构化数据;

Changeset: 一种描述文档更改的数据格式,用来表示整个文档的对前端说一次修改;

ClientVars  表示一篇文档的初始化数据,香港云服务器一般由连续的个线changeset组合而成;

符号解释

​​|​​ :移动光标;

​​·​​:叠加;

正文

OT算法

什么是OT算法呢?我们先从头说起,如果要实现一个多人共同编辑文档的文档功能,我们最简单暴力的需啥做法是啥?

编辑锁

顾名思义,假如A在编辑文档,技术服务端直接将这个文档加锁,B如果在这个时候也加入了编辑,由于锁的存在,B的编辑直接被丢弃。可以看出,这种编辑锁的实现方式非常粗暴,体验极其糟糕,当然了,在很多公司(比如我们的某死对头公司)的一些wiki系统就是用这种实现方式,由于这种实现方式比较简单,而且体验很糟糕(内容丢失

& 无法实时),我们这里就不做讨论了。Linux中的diff-patch

Linux中有两个命令:diff和patch;如果我们能在JS中实现这套算法,那么多人协同编辑可以这样做:

用户打开文档后和服务端建立长链接,保存文档副本;用户编辑的时候如果有停顿(比如3s),则将现有的网站模板文档和副本进行diff对比,将结果传给服务端,更新副本;服务端更新文档,将diff结果通过长链接通知到其它用户,其它用户使用patch方法更新本地的文档;

我们来测试下:

# 本地文档

$ echo 复仇者联盟

钢铁侠

美国队长 > test-local.txt

# 生成用户A编辑后的文档

$ echo 复仇者联盟

钢铁侠

绿巨人 > test-userA.txt

# diff两个文档

$ diff test-local.txt test-userA.txt > diff-test.patch

# 查看diff-test.patch内容

$ cat diff-test.patch

3c3

< 美国队长

---

> 绿巨人

从diff-test.patch内容可以看出,已经找出了两个文档不同的地方,然后我们再模拟下用户B的行为:

# 生成用户B编辑的文档

$ echo 复仇者联盟

黑寡妇

美国队长 > test-userB.txt

# patch方法更新文档

$ patch test-userB.txt < diff-test.patch

# 查看test-userB.txt内容

$ cat test-userB.txt

复仇者联盟

黑寡妇

绿巨人

可以看到,用户B文档的第三行已经更新为了用户A修改后的“绿巨人”。但这种实现方式有个问题,因为他是基于行来进行对比的,就会导致很容易出现冲突,比如:

# 生成文件1

$ echo 复仇者联盟 > local.txt

# 生成文件2

$ echo 复仇者联盟钢铁侠 > userA.txt

# diff对比

$ diff local.txt userA.txt > diff.patch

查看diff.patch内容:

1c1

< 复仇者联盟

---

> 复仇者联盟钢铁侠

这就意味着如果两个人同时修改同一行,那必然就会产生冲突,我们测试下:

# 生成文件3

$ echo 复仇者联盟美国队长 > userB.txt

# patch

$ patch userB.txt < diff.patch

以上我们发现,假如原始文档是“复仇者联盟”,用户A修改为“复仇者联盟钢铁侠”,将diff结果传给服务端,服务端传给用户B,而用户B只是将文档改为了“复仇者联盟美国队长”,直觉上我们可以看出,这两处是不冲突的源码下载,完全可以合并成“复仇者联盟钢铁侠美国队长”,但实际上的patch结果却是这样的:

$ cat userB.txt.rej

很赞哦!(651)