日本电影一区二区_日本va欧美va精品发布_日本黄h兄妹h动漫一区二区三区_日本欧美黄色

可視化+多人協(xié)同技術(shù)原理和案例分享

前言

hi,大家好,我是徐小夕,之前和大家分享了很多可視化低代碼的技術(shù)實踐,最近也做了一款非常有意思的文檔搭建引擎——Nocode/Doc:

可視化+多人協(xié)同技術(shù)原理和案例分享

也做了一些分享:

Nocode/Doc,可視化 零代碼打造下一代文件編輯器

接下來和大家分享另一個比較有意思的話題——多人協(xié)同技術(shù)。

文章大綱

  • 多人協(xié)同技術(shù)方案探討
  • OT和CRDT算法
  • 插曲(互斥鎖(Mutex)原理和代碼實現(xiàn))
  • yjs協(xié)同框架使用
  • yjs多人協(xié)同案例

多人協(xié)同技術(shù)方案探討

多人協(xié)同技術(shù)方案常見的應用場景主要有:

  • 原型工具axure,某刀,mastergo等)
  • 文檔辦公類飛書文檔,釘釘文檔,石墨文檔等)
  • 設計工具(即時設計,figma等)

主要目的是實現(xiàn)多個人同時編輯一份共享資源, 來提高工作效率。

可視化+多人協(xié)同技術(shù)原理和案例分享

拋開已有技術(shù)本身,我們拿最簡單的富文本編輯器為例子, 如果我們想讓它實現(xiàn)多人同時編輯,有哪些可以想到的方案呢?

  • 覆蓋模式

即每個人保存時都強制以自己的版本為主,即保存最后一次修改,這樣會導致的問題是無法實現(xiàn)真正意義上的共享協(xié)作。

  • 鎖模式

也就是對文件”上鎖“。當某個用戶正在編輯文檔時,對此文檔進行加鎖處理,避免多人同時編輯,從而避免文檔的內(nèi)容沖突。 缺點就是用戶體驗不友好,并且需要等待時間。

  • diff 模式

我們可以采用類似 git 的版本管理模式,多人編輯時利用 webrtc / socket 與服務端通信,保存時通過服務端進行差異對比、合并,自動進行沖突處理,再通過服務推送如SSE(服務端實時主動向瀏覽器推送消息的技術(shù))的方式推送給其他人。

弊端是會出現(xiàn)類似 git 修改同一行,純靠服務端無法處理,需要手動處理沖突。

這里給大家推薦一個有意思的庫 NodeGit。

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

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

  • 全功能:幾乎支持 Git 的所有命令,如克隆、提交、拉取、合并等。
  • 高性能:直接調(diào)用 C 庫,提供接近原生速度的性能。
  • 易于集成:作為一個 Node.js 模塊,可輕松融入任何 Node.js 項目,無需額外的構(gòu)建步驟或依賴。
  • 跨平臺:支持 Windows、macOSLinux,讓開發(fā)者可以在各種操作系統(tǒng)上工作。
  • 文檔齊全:提供詳細的 API 文檔和示例代碼,便于理解和使用。
  • 社區(qū)活躍:開源社區(qū)活躍,問題和 PR 能得到及時響應,不斷更新改進。

NodeGit 可以用于多個領(lǐng)域,例如自動化部署、協(xié)作工具、代碼分析、教育工具和 CI/CD 系統(tǒng)等。通過使用 NodeGit,我們能以編程方式訪問和操作 Git 存儲庫,實現(xiàn)更靈活和自動化的版本控制流程。

當然以上這幾種方式很難應對復雜場景的多人協(xié)作。

OT和CRDT算法

OT 算法是一種用于實時協(xié)同編輯的算法,它通過操作 & 轉(zhuǎn)換來實現(xiàn)數(shù)據(jù)的一致性。在 OT 算法中,每個用戶對數(shù)據(jù)的操作(如修改、刪除等)都被記錄下來,并在其他用戶的客戶端進行相應的轉(zhuǎn)換,從而實現(xiàn)多個用戶對同一份數(shù)據(jù)的協(xié)同編輯。

OT 算法的優(yōu)點在于它可以實時地反映用戶的操作,并且可以很好地處理并發(fā)沖突。但是 OT 算法需要在中心化的服務器上進行協(xié)同調(diào)度,因此對于大規(guī)模的分布式系統(tǒng)來說不太適用。

操作 Operational

基于 OT 的協(xié)同編輯核心是:將文檔的每一次修改看作是一個操作,即操作原子化處理,如在第 N 個位置插入一個字符時,客戶端會將操作發(fā)送到服務端去處理。

以quill富文本編輯器舉例, 它通過 retain、insert、delete 三個操作完成整篇文檔的描述與操作,如下:

[ // 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 } ]

相關(guān)地址:https://quilljs.com/docs/delta

Transformation 轉(zhuǎn)換

可視化+多人協(xié)同技術(shù)原理和案例分享

用戶將原子化的操作發(fā)送到服務端時(必須有中央服務器進行調(diào)度), 服務端對多個客戶端的操作進行轉(zhuǎn)換,對客戶端操作中的并發(fā)沖突進行修正,確保當前操作同步到其他設備時得到一致的結(jié)果,因為對沖突的處理都是在服務端完成,所以客戶端得到的結(jié)果一定是一致的,也就是說 OT 算法的結(jié)果保證強一致性。

轉(zhuǎn)換完成后,通過網(wǎng)絡發(fā)送到對應用戶,用戶合并操作,從而得到一致結(jié)果。

這意味著 OT 算法對網(wǎng)絡要求更高,如果某個用戶出現(xiàn)網(wǎng)絡異常,導致一些操作缺失或延遲,那么服務端的轉(zhuǎn)換就會出現(xiàn)問題。

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

CRDT

CRDT 算法全稱 Conflict-free Replicated Data Type,即無沖突復制數(shù)據(jù)類型,是一種基于數(shù)據(jù)結(jié)構(gòu)的無沖突復制數(shù)據(jù)類型算法,它通過數(shù)據(jù)結(jié)構(gòu)的合并來實現(xiàn)數(shù)據(jù)的一致性。

在 CRDT 算法中,每個用戶對數(shù)據(jù)的修改都會被記錄下來,并在其他用戶的客戶端進行合并,以實現(xiàn)數(shù)據(jù)的一致性。CRDT 算法的優(yōu)點在于它可以適用于大規(guī)模的分布式系統(tǒng),并且不需要中心化的服務器進行協(xié)同調(diào)度。

但是,CRDT 算法在處理復雜操作時可能會存在合并沖突的問題,需要設計復雜的合并函數(shù)來解決。

Yjs 是專門為在 web 上構(gòu)建協(xié)同應用程序而設計的CRDT.

CRDT 包含以下兩種:

  • CmRDT:基于操作的 CRDT,OP-based-CRDT
  • CvRDT:基于狀態(tài)的 CRDT,State-based CRDT

基于狀態(tài)的 CRDT 更容易設計和實現(xiàn),每個 CRDT 的整個狀態(tài)最終都必須傳輸給其他每個副本,每個副本之間通過同步全量狀態(tài)達到最終一致狀態(tài),這可能開銷很大;

而基于操作的 CRDT 只傳輸更新操作,各副本之間通過同步操作來達到最終一致狀態(tài),通常很小。

穿插一個小概念:

向量時鐘Vector Clock),它是一種在分布式系統(tǒng)中用于記錄事件順序的時間戳機制。它的主要目的是在分布式環(huán)境中實現(xiàn)事件的并發(fā)控制和一致性。

向量時鐘的基本思想是為系統(tǒng)中的每個節(jié)點維護一個向量,其中每個分量對應一個節(jié)點,用于記錄該節(jié)點的事件發(fā)生次數(shù)。當一個節(jié)點發(fā)生事件時,它會增加自己分量的值。向量時鐘的關(guān)鍵是在不同節(jié)點之間傳遞這些向量,并在合并時確保一致性。

目前協(xié)同算法底層都會采用向量時鐘的模式來設計操作算法。

插曲(互斥鎖(Mutex)原理和代碼實現(xiàn))

先上代碼:

const createMutex = () => { let token = true return (f, g) => { if (token) { token = false try { f() } finally { token = true } } else if (g !== undefined) { g() } }}

它用于創(chuàng)建一個互斥鎖(Mutex)。互斥鎖是一種用于控制資源訪問的機制,確保在任何給定的時間只有一個線程(在這里可以理解為一個函數(shù)調(diào)用)可以訪問被保護的資源或代碼塊。

下面是對代碼中每個部分的解釋:

  • let token = true:創(chuàng)建一個名為token的變量,并將其初始化為true。token用于表示互斥鎖的狀態(tài)。
  • return (f, g) => { … }:返回一個箭頭函數(shù),該函數(shù)接受兩個參數(shù)f和g。
  • if (token) { … }:如果token為true,表示互斥鎖可用。
  • token = false:將token設置為false,表示當前函數(shù)獲取了互斥鎖。
  • try { f() } finally { token = true }:在try塊中執(zhí)行傳入的函數(shù)f。如果在執(zhí)行f的過程中發(fā)生異常,會跳轉(zhuǎn)到finally塊中。在finally塊中,將token重新設置為true,表示釋放互斥鎖。
  • else if (g !== undefined) { g() }:如果token為false,表示互斥鎖已被其他函數(shù)獲取。如果同時還傳遞了第二個參數(shù)g,則執(zhí)行g(shù)函數(shù)。

通過這種方式,createMutex 函數(shù)創(chuàng)建了一個簡單的互斥鎖機制。只有在互斥鎖可用時,才能執(zhí)行f函數(shù)。如果互斥鎖已被其他函數(shù)獲取,將跳過f函數(shù)的執(zhí)行,并在可能的情況下執(zhí)行g(shù)函數(shù)。

這種互斥鎖的實現(xiàn)通常用于在多線程或異步環(huán)境中確保對共享資源的安全訪問。

yjs協(xié)同框架使用

Yjs 本身是一個數(shù)據(jù)結(jié)構(gòu),原理是:當多人協(xié)作時,對于文檔內(nèi)容修改,通過中間層將文檔數(shù)據(jù)轉(zhuǎn)換成 CRDT 數(shù)據(jù);通過 CRDT 進行數(shù)據(jù)數(shù)據(jù)更新這種增量的同步,通過中間層將 CRDT 的數(shù)據(jù)轉(zhuǎn)換成文檔數(shù)據(jù),另一個協(xié)作方就能看到對方內(nèi)容的更新。

中間內(nèi)容的更新是基于 Yjs 數(shù)據(jù)結(jié)構(gòu)進行的,沖突處理等核心都是 Yjs 承擔的,通信基于 websocket 或 webrtc,所以我們只需要簡單的使用就可以實現(xiàn)多人協(xié)同的應用。

下面是我總結(jié)的一個結(jié)構(gòu):

可視化+多人協(xié)同技術(shù)原理和案例分享

Yjs 基于數(shù)據(jù)結(jié)構(gòu)層面處理沖突,比 OT 更加穩(wěn)健,對復雜網(wǎng)絡的適應性更強。網(wǎng)絡延時或離線編輯對數(shù)據(jù)結(jié)構(gòu)來說,處理沒有任何差異。

我總結(jié)了一下它的幾個核心特點:

  • 協(xié)同列表及光標位置

Yjs 提供的 Awareness(意識)模塊,名如其意,讓協(xié)作者能夠意識到其他人的位置在哪,有效避免沖突可能性。

  • 離線編輯

基于 CRDT 的內(nèi)容合并,天然支持離線編輯,瀏覽器端做本地化存儲。

  • 版本歷史支持

Yjs 自身提供了快照機制,保存歷史版本不用保存全量數(shù)據(jù),只是基于 Yjs 打一個快照,后續(xù)基于快照恢復歷史版本。

  • 系統(tǒng)編輯人數(shù)上限

上限人數(shù)很高,可支持很多人同時編輯。

目前主流的 figma 也是采用的 CRDT 開發(fā)協(xié)同編輯功能。

yjs使用

可視化+多人協(xié)同技術(shù)原理和案例分享

以上我根據(jù)自己的理解整理了一下yjs的核心模塊。接下來我以數(shù)組結(jié)構(gòu)為例子給大家介紹一下它的用法:

import * as Y from 'yjs'const ydoc = new Y.Doc()// 1: 定義一個類型為數(shù)組的共享數(shù)據(jù)結(jié)構(gòu)const yarray = ydoc.getArray('my doc') // 2. 向數(shù)組中插入數(shù)據(jù),在第一個位置插入3條數(shù)據(jù)yarray.insert(0, [1, 2, 3]) // 3. 在第二個位置刪除一條數(shù)據(jù)yarray.delete(1, 1)// 4. 獲取可用的結(jié)果yarray.toArray() // => [1, 3]// 5. 監(jiān)聽數(shù)據(jù)變化,執(zhí)行操作yarray.observeDeep((event) => { console.log(event)})// 將連續(xù)的操作合并到transact 中ydoc.transact(() => { yarray.insert(1, ['a', 'b']) yarray.delete(2, 2) // deletes 'b' and 2}) // => [{ retain: 1 }, { insert: ['a'] }, { delete: 1 }]

transact方法用于執(zhí)行事務操作。事務是共享文檔上的一系列更改,這些更改會在一個事務中進行處理,以保證數(shù)據(jù)的一致性和正確性。每個事務都會觸發(fā)Observer調(diào)用和update事件,我們可以在這些事件中進行相應的處理。

通過將更改捆綁到單個事務中,可以減少事件調(diào)用的次數(shù),并確保數(shù)據(jù)的一致性。在事務中,我們可以進行多種操作,如插入、刪除、修改等。

yjs多人協(xié)同案例

可視化+多人協(xié)同技術(shù)原理和案例分享

相關(guān)新聞

聯(lián)系我們
聯(lián)系我們
公眾號
公眾號
在線咨詢
分享本頁
返回頂部
西城区| 汉源县| 团风县| 义乌市| 祥云县| 松原市| 黄山市| 克什克腾旗| 云龙县| 馆陶县| 达州市| 张家川| 瓮安县| 清流县| 原平市| 吉林市| 安平县| 镇宁| 新竹市| 五峰| 墨玉县| 洛南县| 金沙县| 微山县| 辛集市| 华亭县| 永福县| 东山县| 斗六市| 岑巩县| 荔波县| 万荣县| 保康县| 高邮市| 卓尼县| 南雄市| 冀州市| 澄江县| 孟州市| 平安县| 资溪县|