学习yjs过程中自己翻译的文档。
感知信息(用户状态)指的是多人在线协作编辑下其他编辑者的在线状态和信息,例如他人的光标信息,用户标识颜色。这些统称为感知信息, yjs专门提供了一个对象用来存储这些信息。
question: 为什么用单独的字段存储这些信息?
官方文档的解释是这些信息并不属于文档信息的一部分,更像是一种辅助多人编辑的时效性信息,未来也不会持久化到数据,所以作为一个单独的对象信息是合理的, 在线协作编辑下,这些信息往往在用户离线或者离开编辑页面后就失去意义了。
以下是官方提供的一段实例代码:
js
目前感知信息(Awareness)字段还没有规范化,可以自定义一些字段,不过需要注意现有的支持yjs协作的编辑器通常会使用cursor和user字段来记录光标位置和用户信息,这些编辑器都接收Awareness实例来获取光标信息,例如quill:
js
yjs提供了专门的库用来支持离线下操作。y-indexeddb用于将文档数据同步到浏览器的indexDB数据库中,官网使用示例如下:
js
通过监听实例的async
事件可以在本地数据加载时执行相关代码:
js
另外官方提到使用y-indexeddb的优点是当服务器或其他分布式方有数据丢失时yjs也能依靠本地数据库中的存储在下次更新中自动修复。其实就是相当于本地缓存 的意思,看样子官方还是推荐使用y-indexeddb作为本地缓存的。
通过将应用程序的数据托管到y-indexeddb可以轻易的构建一个离线的网页应用程序或网站。
不过y-indexeddb只充当数据库的作用,模拟服务器端的controller和server层需要使用浏览器提供的Server Worker API来实现。 不过我没有使用过这个API,这里只附上其在MDN中的文档地址
文档是一堆序列化的数据结构,你可以轻易的设想出一篇文档的数据对象可能具有的结构和属性,例如一篇简单的word文档,最顶层document Object下可能具有页眉(header field),内容(content field),页脚(footer field)等等。现在我们有了一个文档对象可以对这个文档对象进行编辑(增删改查),并通过服务器分发同步到其他客户端实现同步,但是当冲突和并发发生的时候文档数据可不会自己处理这些情况,如何保证在复杂和高频的增删修改下文档数据的最终一致性,这正是yjs做的事情。
但并不是把文件对象光秃秃的扔给yjs实例他就能处理了,yjs的分布式冲突处理能力是基于自身提供的共享数据类型来实现的,我们需要将普通的文档对象转换为yjs提供的共享数据对象,这样yjs才能正确处理并解决数据冲突。
以下是官网提供的文档示例:
js
除了yarray,yjs还提供了其他共享数据类型
在yjs中,所有的数据修改都应该通过发起事务(Transactions)来实现。当你调用方法修改数组对象时(e.g. yarray.insert(..)),实际上yjs内部隐式的创建了事务来执行修改。 以下示例展示了如何显示的创建事务并修改数据:
js
每次事务的修改都会触发事件的监听,所以最好尽可能的合并修改到一个事务中以减少不需要的监听触发。
yjs事件的触发遵循以下顺序:
ydoc.on('beforeTransaction', event => { .. })
事务执行前调用ydoc.on('beforeObserverCalls', event => {})
事务执行后但是还没开始触发监听ytype.observe(event => { .. })
- 监听器被调用ytype.observeDeep(event => { .. })
- 深层监听器被调用ydoc.on('afterTransaction', event => {})
- - 事务执行完成后ydoc.on('update', update => { .. })
- - 其他客户端修改触发的更新事件可以看到其他客户端的修改会触发update事件,所以尽量合并事件减少事务次数是必要的。