Frontiers
Frontiers 是 Loro 通过识别“前沿”操作(即尚未被后续操作覆盖的最新操作)来紧凑表示文档版本的方法。
Frontiers 是什么?
你可以把 Frontiers 看作文档历史上的书签。与列出每位协作者全部更改的版本向量不同,Frontiers 只指向边界操作,所有祖先通过因果关系被隐式包含。
基本用法
import { } from "loro-crdt";
const = new ();
const = .("content");
.(0, "Hello World");
// 获取当前 frontiers(通常只有 1~2 个元素)
const = .();
.(); // [{ peer: "...", counter: 0 }]
// 使用 frontiers 保存检查点
const = .();
.(5, " Beautiful");
// 恢复到检查点
.();
.(.()); // 回到 "Hello World"什么时候使用 Frontiers
Frontiers 适用于:
- 创建检查点——为文档历史打标签
- 时光旅行——高效跳转到特定操作
- 节省存储——即便协作者众多仍保持紧凑(通常 1~2 个元素,而版本向量需 N 项)
- 记录里程碑——保存重要状态
快速对比
| 维度 | Frontiers | 版本向量 |
|---|---|---|
| 大小 | 通常 1~2 个元素 | 随节点数量增长 |
| 用途 | 检查点、时光旅行 | 同步、差异比较 |
| 存储 | 非常紧凑 | 节点越多越大 |
| 未知操作 | 无法判断包含哪些操作 | 可以精确获知包含的操作 |
实战示例
import { } from "loro-crdt";
const = new ();
const = .("content");
const = new ();
// 使用 frontiers 保存检查点
.(0, "Draft version");
.("draft", .());
// 继续修改
.(0, 5);
.(0, "Final");
.("final", .());
// 恢复任意检查点
.(.("draft"));
.(.()); // "Draft version"重要限制
Frontiers 在面对未知操作时有一个限制:
- 当某个 Frontier 指向你尚未获取的操作时,你无法确定该版本包含了哪些具体操作 ID
- 版本向量没有此限制:它显式记录所有 peer 及其操作计数,因此总能知道确切包含的操作
示例:
import { } from "loro-crdt";
// 如果你收到 frontier [{ peer: "unknown-peer", counter: 42 }]
// 在缺少 "unknown-peer" 的操作时:
// - Frontiers:无法判断包含哪些具体操作
// - 版本向量:会显示 { "unknown-peer": 43 },明确表示包含 0~42 的操作
const = new ();
const = .();
// Frontiers 虽然紧凑,但要了解完整信息需要操作历史因此,Frontiers 更适合你能访问操作历史的场景(例如本地文档的检查点),而在不同节点之间同步时,如果无法共享完整历史,则更建议使用版本向量。
与版本向量互转
Loro 支持两种表示之间的无缝转换:
import { } from "loro-crdt";
const = new ();
const = .();
const = .(); // 转成版本向量
const = .(); // 再转回 frontiers进一步了解
想深入理解 Frontiers 如何结合 DAG 结构与因果顺序,请参阅版本深潜。