Skip to content

第 11 章:冷启动快照与持久化 ​

1. 为什么 native Home 需要 display snapshot ​

钱包 Home 的实时数据很多:Portfolio、Market、Banner、History、NFT、DeFi、Perps、能力拓扑。冷启动时如果等所有 API 重新完成,native container 只能显示 loading skeleton,首屏会慢且几何不稳定。

项目选择把“可展示的最小投影”持久化下来:它不是完整业务状态,也不是可以执行旧 command 的缓存,而是按 owner 分区的 display snapshot。

2. 存储结构 ​

快照协议在 homeDisplaySnapshotTypes.ts 中定义:

text
route(ownerScopeKey)
  ├── currentGeneration
  ├── previousGeneration
  └── partitionId

manifest(partitionId, generation)
  ├── critical chunk
  ├── banner chunk
  ├── portfolio chunk
  ├── market chunk
  └── optional source chunks

关键常量:

常量值意义
HOME_DISPLAY_SNAPSHOT_SCHEMA_VERSION1snapshot 数据版本
HOME_DISPLAY_SNAPSHOT_MAX_CHUNK_BYTES1 MiB单 source chunk 上限
HOME_DISPLAY_SNAPSHOT_MAX_CRITICAL_BYTES128 KiB首屏 critical chunk 上限
HOME_DISPLAY_SNAPSHOT_MAX_ROUTES16route index 的边界
native storage max record2 MiBnative 存储工厂限制

3. 为什么拆成 critical + source chunks ​

critical 保存 shell/navigation 等能够尽快决定页面形状的内容;source chunks 保存 banner、portfolio、market 等按来源可独立读取的数据。

loadPreparedHomeDisplaySnapshot.native.ts 还会拒绝仅有 navigation、没有可渲染 portfolio data 的 snapshot;shell.kind === 'loading' 也会被当作 cache miss。缓存命中不是“有 JSON 就算成功”,而是必须足够构造可见首屏。

4. Projection 与 restore 的边界 ​

homeDisplaySnapshotData.ts 有两套方向:

  • projectHomeDisplaySnapshotRecord:从运行时 payload 提取允许持久化的字段,删掉不应落盘的运行时/隐藏细节;
  • restoreHomeDisplaySnapshotRecord:从磁盘恢复默认结构,再叠加 persisted 字段。

Portfolio 和 Market 还会重新计算 row ids;banner/DeFi/NFT/History/Perps 通过 source-specific snapshot keys 做 allowlist。这是“持久化的是展示投影,不是把整个 Store JSON dump 到磁盘”。

5. generation 与 previous generation ​

route 先指向新 generation,manifest 再引用 chunks。若新 generation 写到一半失败,读取 route 后可以尝试 previous generation;只有完整 manifest、字节长度、schema、owner、partition、generation 和 content signature 都匹配时才接受。

这种双 generation 设计把“部分写入”降级为旧缓存命中,而不是半个 snapshot 被当作新数据。

6. persist queue 的取舍 ​

homeDisplaySnapshotPersistQueue.ts 测试覆盖了:

  • 快速连续 commit 合并成一次物理 generation;
  • unchanged chunks 通过 content signature 复用;
  • 仅 selected tab 改变时不重新写一整代数据;
  • owner partition 相互隔离;
  • 并发 owner write 会重试 route index;
  • confirmed header 不被 pending/unavailable snapshot 覆盖;
  • superseded chunk 即使原 manifest 已退休也会清理。

它本质上是一个“小型 append/commit protocol”,目标不是数据库级事务,而是让 Home 首屏在 crash、切账户、快速刷新和频繁状态变化下保持可恢复。

7. 缓存不能提供什么 ​

快照不提供最新余额、不提供授权、不提供旧 command 的可执行性。Renderer 必须把缓存当 display seed,实时 Store 和当前 owner 才是最终真相。

基于 app-monorepo 2026-07-31 源码快照整理 · 非官方文档