亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

比較優先考慮本地的框架和方法

任何足够先进的技术,在我们眼里都跟魔法差不多。

前端数据库

云应用程序就像是魔法。你在笔记本电脑上的 Google 文档里输入文字,它就会神奇地出现在你的手机上了。或者你在像 Replit 这样的在线编辑器上写代码,你的整个团队就可以一起编写代码了。

但,就像變戲法一樣,我們都知道在表面之下發生了很多我們看不到的事情。而,就像變戲法一樣,當它出錯時,它會變得非常糟糕,糟到極點。比如當你在寫一個 Google 文檔,網絡出了問題,文檔就卡住了。你無法進行編輯,因為文檔無法更新。突然間,你就想回到可以本地操作的 Windows 95 時代。

幸運的是,本地技術並沒有消失。事實上,本地技術正在通過一些將你的數據放在首位的本地優先框架迎來復興。如果雲端在那兒,當然很棒;如果沒有雲端,那就隨它去吧,¯(ツ)/¯。這是一個如此新興的領域,正在開發幾個不同的本地優先框架從不同角度解決這個問題。這裡,我們想強調一些,讓你知道一些本地優先應用的特點。

使用 CRDT 合并数据的

备注:CRDT 是 Conflict-free Replicated Data Type 的缩写,适用于分布式系统中数据的合并操作。

2019年,剑桥大学计算机科学家Martin Kleppmann(著有《设计数据密集型应用》)与数字研究实验室Ink & Switch的作者们共同发布了一份宣言,题为“本地优先的软件:您拥有自己的数据,即使有云的宣言”(Local-first software: you own your data, in spite of the cloud)。

宣言阐述了他们对这种云优先的数据存储模式出错的看法。首先,云应用程序在离线时无法使用,限制了可用性,使得用户体验大打折扣。但这还只是问题的一部分。当数据主要存储在云端时,服务提供商对访问和保存拥有最终控制权,用户几乎成了自己数据的“借用人”。在不同云服务之间迁移数据可能非常困难,一旦云服务关闭,用户将失去对数据和工作的访问权。

这份宣言提出了本地优先软件的七个理念:

  1. 无需加载动画: 通过处理本地数据实现快速性能
  2. 多设备支持: 在所有用户的设备上无缝同步
  3. 离线可用: 无需互联网连接即可实现全读写功能
  4. 实时协作: 多用户可以实时编辑
  5. 长期可用: 可访问和编辑数十年的数据,远超服务器寿命
  6. 数据隐私: 加密的数据对于服务提供商来说是不可访问的
  7. 用户掌控: 数据的所有权,包括复制、修改和删除的权限

他们提出了一些技术概念来实现这些目标,其中最关键的一个是无冲突的复制数据类型(CRDT)。CRDT 是一种数据结构,使数据集的多个副本能够独立并行地更新,无需副本间协调,同时确保所有副本最终都会达到一致的状态。这使得它们非常适合本地优先的软件架构。CRDT 的关键特点包括:

  • 强大的最终一致性。 在接收到相同的更新集后,所有副本最终会收敛到相同的状态,无论这些更新的接收顺序如何
  • 更新的顺序无关性。 更新的执行顺序不会影响最终的状态
  • 更新的结合性。 更新可以任意分组并以任何顺序应用

假设你们有两个共同编辑的文本文件。你们可以各自离线工作,而 CRDT 负责处理合并。为每个字符和操作分配唯一的标识符,使系统能够智能地跟踪和合并更改。例如,如果一个用户在文档开头插入文本,另一个用户在文档末尾添加内容,CRDT 算法可以无缝地整合这两个修改而不会发生冲突。

Ink & Switch 发布了 automerge,它能自动实现这种合并。如果你有两个正在 协作编辑 的文档,你可以使用 automerge 来进行并发编辑。

    import { next as Automerge } from "@automerge/automerge"

    let doc = Automerge.from({text: "hello world"})

    // 将文档分支并进行修改
    let forked = Automerge.clone(doc)
    forked = Automerge.change(forked, d => {
        // 在索引5处插入 ' wonderful', 不删除任何内容
        Automerge.splice(d, ["text"], 5, 0, " wonderful")
    })

    // 对原始文档进行并发更改
    doc = Automerge.change(doc, d => {
        // 在起始处插入 'Greetings', 并删除前5个字符
        Automerge.splice(d, ["text"], 0, 5, "Greetings")
    })

    // 合并更改
    doc = Automerge.merge(doc, forked)

    // 打印合并后的结果为: "Greetings wonderful world"
    console.log(doc.text) // "Greetings wonderful world"

全屏模式 退出全屏

这种方法实现了真正的本地优先协作,让用户可以离线工作,并在重新连接时同步修改,而无需中央服务器解决冲突。

将数据与PouchDB同步

“同步的数据库!”是PouchDB首页上喊道。PouchDB 是另一个以本地优先、同步为特点的新数据库。PouchDB 是一个运行在浏览器中的 JavaScript 数据库,允许开发人员创建可以离线工作的应用,并在在线时与服务器端数据库同步。它旨在兼容(并受 Apache 的 NoSQL CouchDB 启发)。

PouchDB 的核心理念与本地优先宣言非常一致,

  • 离线优先: 完全离线使用,有网络连接时自动同步
  • 多设备同步: 数据在多个设备间无缝同步
  • 开源: 允许社区贡献和审查
  • 跨平台: 可以在浏览器、Node.js 以及移动设备上运行

PouchDB 采用以文档为基础的数据模型,其中每个文档都是一个 JSON 格式的对象。下面是一个简单的示例,展示如何创建和查询 PouchDB 数据库:

    // 创建数据库
    var db = new PouchDB('my_database');

    // 添加文档
    db.put({
      _id: 'mittens',
      name: 'Mittens',
      species: 'cat',
      age: 3
    }).then(function () {
      // 查找所有 'cat' 类型的文档
      return db.find({
        selector: {species: 'cat'}
      });
    }).then(function (result) {
      console.log(result.docs);
    }).catch(function (err) {
      console.log(err);
    });

全屏切换,退出全屏

PouchDB的一个关键特性是它的同步功能。在线时,PouchDB可以与CouchDB服务器进行同步,从而实现实时协作:

    var localDB = new PouchDB('my_database');
    var remoteDB = new PouchDB('http://example.com/my_database');

    localDB.sync(remoteDB, {
      live: true,
      retry: true
    }).on('change', function (change) {
      console.log('数据变化:', change);
    }).on('error', function (err) {
      console.log('同步出错:', err);
    });

全屏 退出全屏

PouchDB 不使用 CRDT 来解决冲突。相反,它使用一种基于版本历史记录的确定性算法。当发生冲突时,PouchDB 会选择一个胜出的版本,并将其他版本标记为冲突,这些冲突可以被手动访问和解决。如果你想深入了解,这里有一篇关于CouchDB 如何实现最终一致性的好文章。

虽然 PouchDB 提供了一个强大的离线优先应用程序解决方案,但它也存在一些挑战。大量数据可能会影响性能。和其他本地优先的解决方案类似,开发人员在设计时需要仔细考虑数据建模和冲突解决策略。

PouchDB 向我们表明,本地优先不仅关乎新的前沿技术,它还关乎于重新构想现有的数据库,使之更适合于离线成为常态的世界。
使用 ElectricSQL 实现 Postgres 同步

ElectricSQL 让我们在 Neon 特别兴奋,因为它使用 Postgres 作为底层数据存储。它比本地优先解决方案更进一步:ElectricSQL 的核心组件是一个名为 Sync Engine 的服务,它运行在你的服务器上,连接本地设备和你的 Postgres 数据库。因此,你可以用 ElectricSQL 作为本地优先架构的关键部分,但它并不能满足所有需求。

数据库

ElectricSQL通过Postgres逻辑复制监听您的数据库中的任何变化,并高效地将少量数据同步到连接的本地应用。

同步引擎只是服务器端的一部分,你仍然需要一个本地组件来处理数据。ElectricSQL 提供了一个 Typescript 客户端,它提供了从同步引擎获取数据的基本功能:

    import { ShapeStream, Shape } from '@electric-sql/client'

    const stream = new ShapeStream({
      url: `${BASE_URL}/v1/shape/foo`,
    })
    const shape = new Shape(stream)

    // 返回一个 Promise,解析结果为最新的形状数据,当数据完全加载时。
    await shape.value

    // 当形状更新时,将最新的形状数据传递给订阅者。
    shape.subscribe(shapeData => {
      // shapeData 是一个 Map,包含形状中每一行的最新数据。
    }

全屏,进入 / 退出

注意
如果你在使用 ElectricSQL 和 Neon,请通过 Neon 的界面启用数据库的逻辑复制以确保其正常运作。

更多使用ElectricSQL进行本地优先的例子可以在他们的GitHub仓库中的examples目录里找到,网址为https://github.com/electric-sql/electric/tree/main/examples

默认为本地

如果你曾经好奇过 Linear、Figma 或 Excalidraw 是如何工作的,这就是它们工作的方式。本地优先的方法正在改变我们对数据所有权和应用架构的思考方式。它们不仅解决了离线问题,还促使我们重新考虑用户与数据之间的关系。

这绝对不是一份详尽无遗的清单。虽然大多数本地优先框架大致遵循上述方法之一,每个框架都有其独特实现,可能使其成为最适合您的选择。要进行更深入的研究,这里有一个评估范式,用于评估本地解决方案,还有一个本地工具列表,您可以进行探索。通过将数据交还给用户,这些框架正为更具弹性、尊重隐私和以用户为中心的应用程序铺平道路。

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消