Web3 开发平台 Convex 近期完成由 a16z 领投的 2600 万美元 A 轮融资,测试版即将上线。
原文标题:《Convex 完成 2600 万美元融资,能否重构 Web3 应用构建方式?》
撰文:老雅痞
2022 年 4 月 27 日,Web 开发人员管理平台 Convex 宣布完成数额为 2600 万美元的 A 轮融资,本轮融资由 a16z 领投,并且 a16z 普通合伙人 Martin Casado 将加入 Convex 董事会。除此之外,还包括 GitHub 前 CEO Nat Friedman、Alphabet 董事会成员 Ram Shriram,以及 Creative Artists Agency 创始人 Michael Ovitz 等天使投资人。Convex 预计将在接下来几周时间内向更多开发者开放测试版。


开发人员在使用 JavaScript 或 TypeScript 函数与共享状态进行交互时,可以将该状态绑定到他的反应式应用程序中。除此之外,Convex 完全无服务器,可自动处理缓存和缩放。
Convex 致力于从根本上改变软件在网络上的构建方式以及构建人员的操作逻辑。Convex 希望可以使各种规模的工程团队能够构建快速、可靠的动态应用程序,而无需复杂的后端工程或数据库管理。
Convex 的团队在管理复杂应用程序和成长中团队中的关键共享用户状态方面拥有相当丰富的经验。其曾领导过 EB 级存储项目、设计过具有数万亿条记录的定制全球数据库、构建了一些较为流行的 Web 应用程序以及将桌面和移动软件交付到数十亿台设备上的技术专家。
Convex 创建了一个由本地 React 前端组成的应用程序,该前端将数据存储在远程 Convex 部署中。

该应用程序完全由本地目录中的文件定义,其本质上是在云中运行的分布式应用程序。持久共享状态存储在 Convex 中,可用于运行开发者的应用程序以及任何希望与之交互的浏览器。
Convex 由三个主要成分组成:
接下来,笔者将逐一进行简单介绍:
开发者的 Convex 部署包含保存应用数据的图表。最初,其部署是不包含图表或文档的。一旦其将第一个文档添加到其中,相应的图表就会立即存在。开发者无需预先指定任何模式,或主动创建任何图表。Convex 文档与 JavaScript 对象非常相似。它们具有字段和值,开发者可以在其中嵌套数组或对象。它们还可以包含对其他表中其他文档的引用。
但是如何通过使用数据输入和输出这些图表呢?在 Convex 中,开发人员可以通过使用函数来实现。Convex 函数是使用 JavaScript 或 TypeScript 编写的,由 Convex 在开发者的部署中运行。其在用户浏览器中运行的应用程序不会直接向数据库读取和写入值。相反,它调用开发者的函数。开发者的函数可以通过传递给 Convex 函数与其数据进行交互。这会公开数据的稳定版本。同时,这些函数可以执行复杂的聚合、使用 NPM 库等等。他们可以做大部分 JavaScript 可以做的事情,但也并非全部。
另外,Convex 函数必须是确定性的。确定性意味着无论开发者的函数运行多少次,只要给它相同的参数,它就会有相同的反馈并返回相同的值。包括调用 HTTP API、将数据写入磁盘或将数据存储在 Convex 表中。

Convex 函数不能执行任何网络调用或磁盘 I/O。但是该 DatabaseWriter 对象支持确定性更新,因此开发者的函数可以针对 Convex 表中包含的数据进行操作。Convex 函数可以使用某些形式的随机性和时间。
Convex 提供了一个「种子」强伪随机数生成器(Math.random ())以便它可以保证函数的确定性。随机数生成器的种子是函数的隐式参数。
当开发者的 Convex 函数开始确保其函数中的逻辑是可重现的时,系统时间也将被「冻结」。Date.now () 将在整个函数执行过程中返回相同的结果。
而当开发者编写 Convex 函数时,不必考虑维护这些确定性属性。Convex 会在其进行时提供有用的错误消息,因此开发者可以避免因意外而做一些被禁止的事情。
Convex 函数主要包括两种类型:
1)查询函数
查询函数不会写入 Convex 表,它们只会从中读取。

确定性在查询函数中是必要的,因为它可以支持 Convex 的两个重要特性。查询函数可以反应式加载。这意味着 Convex 将在结果更改时将函数的结果推送到客户端。Convex 之所以能够做到这一点,是因为 Convex:
当底层数据发生变化时,Convex 可以安全地重新执行函数,而不必担心重复副作用。
Convex 自动缓存查询函数结果。因为查询函数在给定相同参数和数据库状态的情况下总是返回相同的结果,所以 Convex 可以确信缓存值是完全正确的。当底层数据发生变化时,Convex 会检测到缓存值不再有效并重新计算它。
2)突变函数
突变函数是开发人员在 Convex 中更改数据的方式。

当开发人员用 mutation 包装器包装一个 Convex 函数时,它将被 Convex 归类为突变函数。每个突变都是在一致的数据库快照上运行的事务。这意味着突变将始终以原子方式提交。无需考虑在事务中间更改开发人员身下的数据,也无需管理锁。
开发人员的应用程序可以通过客户端库与 Convex 交互。客户端库位于开发人员的前端代码中,是应用程序的接口,其主要有两种用途:
Convex 可以帮助开发人员管理其全局状态并消除对传统数据库的需求。Convex 旨在与无服务器平台合作,并可以同 Netlify 或 Vercel 等服务配对。这些服务提供:
通过 ConvexReactClient 创建 WebSocket 连接到开发人员的 Convex 部署。这是基于 TCP 的 2 路通信通道。这很重要,因为它允许 Convex 将新的查询结果响应式地推送到客户端,而客户端无需轮询更新。如果互联网连接断开,客户端将自动处理重新连接和重新建立 Convex 会话。
useQuery 开发人员的应用程序使用 React 挂钩从 Convex 加载数据。这个挂钩允许开发者的应用在其 Convex 部署中调用查询函数。该 useQuery 挂钩为其 UI 组件带来了自动反应。像 React 这样的现代响应式 Web 开发框架可以轻松地在本地状态更改时重新呈现 UI 组件,但是构建完全响应式应用程序还需要将更改从数据库状态一直传播到 UI。该 useQuery 挂钩向 Convex 后端发送 WebSocket 消息以创建活动订阅。Convex 透明地监控查询所依赖的所有后端数据,并在查询结果发生变化时自动更新组件。

在引擎下,这个 useQueryReact 钩子:
稍后,如果任何突变插入、更新或删除与读取集重叠的记录,Convex 知道它需要重新计算 listMessages 查询。如果结果 listMessages 更改,则将新值同步到客户端并重新呈现组件。
当 useQuery 挂钩卸载时,Convex 客户端将通知该后端它不再需要此订阅。此数据流可确保开发者的组件在底层数据更改时自动重新渲染。
Convex 订阅提供了一种强大的机制来使动态 UI 组件保持最新,但订阅的简单实现可能会向用户暴露一致性异常。
当客户端上的数据表示与后端数据的有效快照不对应时,就会发生一致性异常。使用基本 HTTP API 的应用程序通常有两种类型的一致性异常:
这些异常会在前端产生很多细微的错误。许多框架要求开发人员在前端实现 hack 和变通方法,以处理后端永远不存在的数据场景。例如:
除此之外,手动处理这些情况既会使前端逻辑复杂化,也会给用户造成混乱的 UI。幸运的是,这些问题在 Convex 中都会得到缓解,因为 Convex 会自动确保开发者的所有查询在给定时间点与后端保持一致。
Convex 同时跟踪所有订阅,并以一致的顺序将所有更改同步到客户端:如果支持一个组件的查询结果在查询另一个组件之前发生更改,则它们将按相应的顺序在本地更新。此外,如果单个突变同时更新多个查询,这些更改将自动传播到客户端。Convex 保证客户端始终看到一致的后端数据视图,表示某个时间点的数据库状态。
useMutation 开发者的应用程序使用 React 挂钩在 Convex 中编辑其数据。这个挂钩允许开发者的应用在其 Convex 部署中调用突变函数。客户端将自动处理重试突变,直到它们被保存。
在内部,开发者的 Convex 部署会跟踪已提交的变更,并确保每个变更仅执行一次,即使客户端重试也是如此。我们称这种突变为幂等性。
突变幂等性很重要,因为它解决了一类常见的错误,即不稳定的互联网连接和重试逻辑导致突变意外执行两次。如果使用者在聊天应用程序中发送了两次消息,就会遇到此错误。突变幂等性保证了此类错误不会发生在 Convex 中。
此外,虽然客户端在飞行中具有突出的突变,但客户端会在用户关闭浏览器选项卡之前警告用户。这意味着当使用者调用一个 Convex 突变时,其可以确保用户的编辑不会丢失。
如上所述,Convex 查询是完全反应式的,因此所有查询结果将在突变后自动更新。
有时开发者可能希望在突变同步到 Convex 后端之前更新 UI。为此,其可以配置自动更新以作为突变的一部分执行。自动更新是对查询结果的临时本地更改,用于使开发者的应用程序更具响应性。
参考资料:
https://docs.convex.dev/getting-started/
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。
