可视化+多人协同技术原理和案例分享

前言

hi,大家好,我是徐小夕,之前和大家分享了很多可视化低代码的技术实践,最近也做了一款非常有意思的文档搭建引擎——Nocode/Doc

d95c0cd804877e2804b6a0f863cad2f1.png

也做了一些分享:

  • Nocode/Doc,可视化+ 零代码打造下一代文件编辑器

  • 爆肝1000小时, Dooring零代码搭建平台3.5正式上线

接下来和大家分享另一个比较有意思的话题——多人协同技术

文章大纲

  • 多人协同技术方案探讨

  • OT和CRDT算法

  • 插曲(互斥锁(Mutex)原理和代码实现)

  • yjs协同框架使用

  • yjs多人协同案例

多人协同技术方案探讨

多人协同技术方案常见的应用场景主要有:

  • 原型工具(axure,某刀,mastergo等)

  • 文档办公类 (飞书文档,钉钉文档,石墨文档等)

  • 设计工具(即时设计,figma等)

主要目的是实现多个人同时编辑一份共享资源, 来提高工作效率。

50b79a410428b7d9258fe8291d86c562.png

抛开已有技术本身,我们拿最简单的富文本编辑器为例子, 如果我们想让它实现多人同时编辑,有哪些可以想到的方案呢?

  • 覆盖模式

即每个人保存时都强制以自己的版本为主,即保存最后一次修改,这样会导致的问题是无法实现真正意义上的共享协作。

  • 锁模式

也就是对文件”上锁“。当某个用户正在编辑文档时,对此文档进行加锁处理,避免多人同时编辑,从而避免文档的内容冲突。 缺点就是用户体验不友好,并且需要等待时间。

  • diff 模式

我们可以采用类似 git 的版本管理模式,多人编辑时利用 webrtc / socket 与服务端通信,保存时通过服务端进行差异对比、合并,自动进行冲突处理,再通过服务推送如SSE(服务端实时主动向浏览器推送消息的技术)的方式推送给其他人。

弊端是会出现类似 git 修改同一行,纯靠服务端无法处理,需要手动处理冲突。

这里给大家推荐一个有意思的库 NodeGit

github地址: https://github.com/nodegit/nodegit

以下是 NodeGit 的一些主要特点:

  • 全功能:几乎支持 Git 的所有命令,如克隆、提交、拉取、合并等。

  • 高性能:直接调用 C 库,提供接近原生速度的性能。

  • 易于集成:作为一个 Node.js 模块,可轻松融入任何 Node.js 项目,无需额外的构建步骤或依赖。

  • 跨平台:支持 Windows、macOS 和 Linux,让开发者可以在各种操作系统上工作。

  • 文档齐全:提供详细的 API 文档和示例代码,便于理解和使用。

  • 社区活跃:开源社区活跃,问题和 PR 能得到及时响应,不断更新改进。

NodeGit 可以用于多个领域,例如自动化部署、协作工具、代码分析、教育工具和 CI/CD 系统等。通过使用 NodeGit,我们能以编程方式访问和操作 Git 存储库,实现更灵活和自动化的版本控制流程。

当然以上这几种方式很难应对复杂场景的多人协作。

OT和CRDT算法

OT 算法是一种用于实时协同编辑的算法,它通过操作 & 转换来实现数据的一致性。在 OT 算法中,每个用户对数据的操作(如修改、删除等)都被记录下来,并在其他用户的客户端进行相应的转换,从而实现多个用户对同一份数据的协同编辑。

OT 算法的优点在于它可以实时地反映用户的操作,并且可以很好地处理并发冲突。但是 OT 算法需要在中心化的服务器上进行协同调度,因此对于大规模的分布式系统来说不太适用。

操作 Operational

基于 OT 的协同编辑核心是:将文档的每一次修改看作是一个操作,即操作原子化处理,如在第 N 个位置插入一个字符时,客户端会将操作发送到服务端去处理。

quill富文本编辑器举例, 它通过 retaininsertdelete 三个操作完成整篇文档的描述与操作,如下:

[// Unbold and italicize "Gandalf"{ retain: 7, attributes: { bold: null, italic: true } },// Keep " the " as is{ retain: 5 },// Insert "White" formatted with color #fff{ insert: 'White', attributes: { color: '#fff' } },// Delete "Grey"{ delete: 4 }]

相关地址:https://quilljs.com/docs/delta

Transformation 转换
d150a5d22bfd826dd33506b3f70bde8e.png

用户将原子化的操作发送到服务端时(必须有中央服务器进行调度), 服务端对多个客户端的操作进行转换,对客户端操作中的并发冲突进行修正,确保当前操作同步到其他设备时得到一致的结果,因为对冲突的处理都是在服务端完成,所以客户端得到的结果一定是一致的,也就是说 OT 算法的结果保证强一致性。

转换完成后,通过网络发送到对应用户,用户合并操作,从而得到一致结果。

这意味着 OT 算法对网络要求更高,如果某个用户出现网络异常,导致一些操作缺失或延迟,那么服务端的转换就会出现问题。

OT算法可视化模型:https://operational-transformation.github.io/index.html

CRDT

CRDT 算法全称 Conflict-free Replicated Data Type,即无冲突复制数据类型,是一种基于数据结构的无冲突复制数据类型算法,它通过数据结构的合并来实现数据的一致性

CRDT 算法中,每个用户对数据的修改都会被记录下来,并在其他用户的客户端进行合并,以实现数据的一致性。CRDT 算法的优点在于它可以适用于大规模的分布式系统,并且不需要中心化的服务器进行协同调度。

但是,CRDT 算法在处理复杂操作时可能会存在合并冲突的问题,需要设计复杂的合并函数来解决。

Yjs 是专门为在 web 上构建协同应用程序而设计的CRDT.

CRDT 包含以下两种:

  • CmRDT:基于操作的 CRDT,OP-based-CRDT

  • CvRDT:基于状态的 CRDT,State-based CRDT

基于状态的 CRDT 更容易设计和实现,每个 CRDT 的整个状态最终都必须传输给其他每个副本,每个副本之间通过同步全量状态达到最终一致状态,这可能开销很大;

而基于操作的 CRDT 只传输更新操作,各副本之间通过同步操作来达到最终一致状态,通常很小。

穿插一个小概念:

向量时钟(Vector Clock),它是一种在分布式系统中用于记录事件顺序的时间戳机制。它的主要目的是在分布式环境中实现事件的并发控制和一致性。

向量时钟的基本思想是为系统中的每个节点维护一个向量,其中每个分量对应一个节点,用于记录该节点的事件发生次数。当一个节点发生事件时,它会增加自己分量的值。向量时钟的关键是在不同节点之间传递这些向量,并在合并时确保一致性。

目前协同算法底层都会采用向量时钟的模式来设计操作算法。

插曲(互斥锁(Mutex)原理和代码实现)

先上代码:

const createMutex = () => {let token = truereturn (f, g) => {if (token) {token = falsetry {f()} finally {token = true}} else if (g !== undefined) {g()}}
}

它用于创建一个互斥锁(Mutex)。互斥锁是一种用于控制资源访问的机制,确保在任何给定的时间只有一个线程(在这里可以理解为一个函数调用)可以访问被保护的资源或代码块

下面是对代码中每个部分的解释:

  • let token = true:创建一个名为token的变量,并将其初始化为true。token用于表示互斥锁的状态。

  • return (f, g) => { ... }:返回一个箭头函数,该函数接受两个参数f和g。

  • if (token) { ... }:如果token为true,表示互斥锁可用。

  • token = false:将token设置为false,表示当前函数获取了互斥锁。

  • try { f() } finally { token = true }:在try块中执行传入的函数f。如果在执行f的过程中发生异常,会跳转到finally块中。在finally块中,将token重新设置为true,表示释放互斥锁。

  • else if (g !== undefined) { g() }:如果token为false,表示互斥锁已被其他函数获取。如果同时还传递了第二个参数g,则执行g函数。

通过这种方式,createMutex 函数创建了一个简单的互斥锁机制。只有在互斥锁可用时,才能执行f函数。如果互斥锁已被其他函数获取,将跳过f函数的执行,并在可能的情况下执行g函数。

这种互斥锁的实现通常用于在多线程或异步环境中确保对共享资源的安全访问

yjs协同框架使用

Yjs 本身是一个数据结构,原理是:当多人协作时,对于文档内容修改,通过中间层将文档数据转换成 CRDT 数据;通过 CRDT 进行数据数据更新这种增量的同步,通过中间层将 CRDT 的数据转换成文档数据,另一个协作方就能看到对方内容的更新。

中间内容的更新是基于 Yjs 数据结构进行的,冲突处理等核心都是 Yjs 承担的,通信基于 websocketwebrtc,所以我们只需要简单的使用就可以实现多人协同的应用。

下面是我总结的一个结构:

13f77f4337e38ccf95806a20723273e5.png

Yjs 基于数据结构层面处理冲突,比 OT 更加稳健,对复杂网络的适应性更强。网络延时或离线编辑对数据结构来说,处理没有任何差异。

我总结了一下它的几个核心特点:

  • 协同列表及光标位置

Yjs 提供的 Awareness(意识)模块,名如其意,让协作者能够意识到其他人的位置在哪,有效避免冲突可能性。

  • 离线编辑

基于 CRDT 的内容合并,天然支持离线编辑,浏览器端做本地化存储。

  • 版本历史支持

Yjs 自身提供了快照机制,保存历史版本不用保存全量数据,只是基于 Yjs 打一个快照,后续基于快照恢复历史版本。

  • 系统编辑人数上限

上限人数很高,可支持很多人同时编辑。

目前主流的 figma 也是采用的 CRDT 开发协同编辑功能。

yjs使用
dc9f4086640f4f6693619b64aa2524f5.png

以上我根据自己的理解整理了一下yjs的核心模块。接下来我以数组结构为例子给大家介绍一下它的用法:

import * as Y from 'yjs'const ydoc = new Y.Doc()// 1: 定义一个类型为数组的共享数据结构
const yarray = ydoc.getArray('my doc') // 2. 向数组中插入数据,在第一个位置插入3条数据
yarray.insert(0, [1, 2, 3]) 
// 3. 在第二个位置删除一条数据
yarray.delete(1, 1)
// 4. 获取可用的结果
yarray.toArray() // => [1, 3]// 5. 监听数据变化,执行操作
yarray.observeDeep((event) => {console.log(event)
})// 将连续的操作合并到transact 中
ydoc.transact(() => {yarray.insert(1, ['a', 'b'])yarray.delete(2, 2) // deletes 'b' and 2
}) // => [{ retain: 1 }, { insert: ['a'] }, { delete: 1 }]

transact方法用于执行事务操作。事务是共享文档上的一系列更改,这些更改会在一个事务中进行处理,以保证数据的一致性和正确性。每个事务都会触发Observer调用和update事件,我们可以在这些事件中进行相应的处理。

通过将更改捆绑到单个事务中,可以减少事件调用的次数,并确保数据的一致性。在事务中,我们可以进行多种操作,如插入、删除、修改等。

yjs多人协同案例

feef638f871da3315ee58fb521c2ad59.png

最后

好啦。这就是本周的更新,预计4月29号会做一波更大规模的更新和功能上线,欢迎随时和我留言反馈,建议,技术交流~

大家也可以关注我的视频号,后续会做更多的零代码技术产品分享~

往期精彩:
  • Nocode/Doc,可视化+ 零代码打造下一代文件编辑器

  • 爆肝1000小时, Dooring零代码搭建平台3.5正式上线

  • 可视化表单&试卷搭建平台技术详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/314005.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web3钱包开发获取测试币-Polygon Mumbai(一)

Web3钱包开发获取测试币-Polygon Mumbai(一) 由于主网区块链上的智能合约需要真正的代币,而部署和使用需要花费真金白银,因此测试网络为 Web3 开发人员提供了一个测试环境,用于部署和测试他们的智能合约,以识别和修复在将智能合约…

大数据第七天

文章目录 吐槽一下这个是怎么需要真的这么大吗? 内核错误内核软死锁(soft lockup)我这个cpu很高吗?大模型都说了不超过80就行了 FinBi安装FinBI下载链接安装时间比较长 吐槽一下 dbeaver 查询hive 数据信息是真的慢,没有一点快的方式&…

Git TortoiseGit 详细安装使用教程

前言 Git 是一个免费的开源分布式版本控制系统,是用来保存工程源代码历史状态的命令行工具,旨在处理从小型到非常大型的项目,速度快、效率高。《请查阅Git详细说明》。TortoiseGit 是 Git 的 Windows Shell 界面工具,基于 Tortoi…

解决问题:TypeError:unsupported operand type(s) for -: ‘float‘ and ‘decimal.Decimal‘

文章目录 一、现象二、解决方案 一、现象 用Pandas 处理数据的时候,想得到增长率,没想到翻车了? import pandas as pddf pd.read_csv(data.csv)df[增长率] ((df[今年] - df[去年]) / (df[今年]))执行一下语句发现报错 TypeError&#xf…

【机器学习】各大模型原理简介

目录 ⛳️推荐 前言 一、神经网络(联结主义)类的模型 二、符号主义类的模型 三、决策树类的模型 四、概率类的模型 五、近邻类的模型 六、集成学习类的模型 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风…

如何使用 ArcGIS Pro 快速为黑白地图配色

对于某些拍摄时间比较久远的地图,限于当时的技术水平只有黑白的地图,针对这种情况,我们可以通过现在的地图为该地图进行配色,这里为大家讲解一下操作方法,希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微…

iPerf 3 测试UDP和TCP方法详解

文章目录 前言一、What is iPerf / iPerf3 ?二、功能1. TCP and SCTP2. UDP3. 其他 三、 Iperf的使用1.Iperf的工作模式2. 通用指令3. 服务端特有选项4. 客户端特有选项5. -t -n参数联系 四、Iperf使用实例1. 调整 TCP 连接1. 1TCP 窗口大小调节1. 2 最大传输单元 (MTU)调整 2…

前端框架技术革新历程:从原生DOM操作、数据双向绑定到虚拟DOM等框架原理深度解析,Web开发与用户体验的共赢

前端的发展与前端框架的发展相辅相成,形成了相互驱动、共同演进的关系。前端技术的进步不仅催生了前端框架的产生,也为其发展提供了源源不断的动力。 前端的发展 前端,即Web前端,是指在创建Web应用程序或网站过程中负责用户界面…

sprinboot+vue集成neo4j图数据库

一 、java后台 1.1 package com.admin.domain;/*** 功能描述:** author wangwei* date 2024-01-15 22:13*/ public class ConnectWeb {private String connectWebId;private String connectWebName;private String connectWebInfo;private String personWebIdAlph…

IntelliJ IDEA2020下使用Maven构建Scala 项目

1.创建maven文件 2.进入pom.xml导入依赖 <!--添加spark的依赖--><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.12</artifactId><version>3.2.1</version></dependency><!--添加scala依…

Golang操作Redis

一. Redis介绍 1.1 简介 Redis是完全开源免费的&#xff0c;遵循BSD协议&#xff0c;是一个高性能的key-value数据库。 Redis与其它的key-value缓存产品有以下三个特点&#xff1a; Redis支持数据持久化&#xff0c;可以见内存中的数据报错在磁盘中&#xff0c;重启的时候可以…

什么是用户体验(UX)文案,为什么它很重要?

网上购物如今比以往任何时候都更加相关。所以我们将以此为例说明什么是用户体验&#xff08;UX&#xff09;文案&#xff0c;以及为什么它很重要。 假设你去了一个在线商店。你需要执行一系列操作&#xff1a; 找到合适的部分选择你感兴趣的产品弄清楚它们是什么&#xff0c;…

使用composer开发自己的扩展包

前言 日常的开发中我们经常用到composer去安装其他人封装好的扩展包&#xff0c;如果你有好的功能代码想分享给其他人使用&#xff0c;就可以使用composer打包成扩展包。其他人用composer安装后就可以使用你的扩展包了。这篇文章教你如何打包自己的composer扩展包。 1.新建仓…

Mediasoup-demo 本地启动步骤(超详细)

Mediasoup-demo 本地启动步骤&#xff08;超详细&#xff09; 一.本人环境 系统&#xff1a;macos13.6.3 node: v16.20.2 npm:8.19.4 python: 3.9.6 二.下载代码 git 下载代码&#xff1a; git clone gitgithub.com:versatica/mediasoup-demo.git 三.代码介绍 下载下来…

微信小程序使用 Vant Weapp 中 Collapse 折叠面板 的问题!

需求&#xff1a;结合Tab 标签页 和 Collapse 折叠面板 组合成显示课本和章节内容&#xff0c;并且用户体验要好点&#xff01; 如下图展示&#xff1a; 问题&#xff1a;如何使用Collapse 折叠面板 将内容循环展示出来&#xff1f; js中的数据是这样的 代码实现&#xff1…

面试宝典(1)——数据库篇(MySQL)

面试宝典&#xff08;1&#xff09;——数据库篇&#xff08;MySQL&#xff09; 1.什么是索引&#xff1f; 索引是一种用于加快数据库查询速度的数据结构。 索引可以帮助数据库快速定位到数据库表中特定列的记录&#xff0c;从而加快数据检索和查询的速度。 通过在表的列上…

webpack 打包优化 - splitChunks

打包时会遇到的问题&#xff1a; 打包文件过大&#xff0c;首屏加载时间过长&#xff0c;js阻塞页面渲染导致白屏改动业务代码后&#xff0c;对于第三方库也会一并重新打包到一个出口文件&#xff0c;浏览器无法利用缓存来减少请求和加载的时间 针对以上两个问题&#xff0c;…

paddlepaddle-gpu安装

背景 之前安装paddlepaddle-gpu遇到各种问题&#xff0c;安装不成功&#xff0c;之前使用了wsldocker的方式&#xff0c;可查看我之前博客&#xff1a;记录paddlepaddle-gpu安装&#xff0c;这要会导致我整个开发流程比较割裂 cuda版本 强烈推荐cuda11.8&#xff0c;paddlep…

【讯为Linux驱动笔记1】申请一个字符设备

Linux下每个设备都需要有一个专属设备号&#xff1a;主设备号 次设备号 【申请字符设备】 主设备号&#xff1a;一类驱动&#xff1a;如&#xff1a;USB驱动 次设备号&#xff1a;这类驱动下的某个设备 如&#xff1a;键盘鼠标 设备号是32位的dev_t类型的&#xff0c;高12位主…

【黑马头条】-day12项目部署和发布-jenkins

文章目录 1 持续集成2 软件开发模式2.1 瀑布模式2.2 敏捷开发2.2.1 迭代开发2.2.2 增量开发 3 Jenkins3.1 Jenkins安装3.1.1 导入镜像3.1.2 配置3.1.3 初始化设置 3.2 插件安装3.3 服务器环境准备3.3.1 Docker安装配置3.3.2 Git安装配置3.3.3 Maven安装配置 3.4 Jenkins工具配置…