Firebase Firestore 的离线持久化并非简单的内存缓存,而是将文档快照、查询结果、挂起的写入等持久化到本地磁盘。移动端 SDK 默认开启这项能力,数据被写入 SQLite 数据库文件;Web SDK 则要求开发者显式启用,底层使用 IndexedDB 存储。两者都有相同的默认缓存容量:40MB。这个数字是 Firestore 自己维护的回收阈值,而不是操作系统或浏览器的硬限制。如果应用长期离线或写入频繁,200 条稍大的文档就可能触及这个上限。因此,弄清缓存大小的配置方式和写满后的行为,比单纯调大数值更重要。

一、离线持久化的存储位置与默认大小
在 Android 平台上,Firestore 的离线数据通常保存在应用私有目录下的 SQLite 数据库文件中,路径类似于 /data/data/应用包名/databases/ 下,数据库名称包含项目 ID 和实例名。iOS 则使用沙盒目录中的本地文件存储。这些文件由 Firestore SDK 内部管理,开发者不应直接修改或删除,否则会导致缓存损坏或同步异常。
Web 端的实现完全不同。Firestore Web SDK 使用浏览器的 IndexedDB 作为持久化后端,当开发者启用离线持久化后,会在 IndexedDB 中创建多个对象仓库,用于保存文档数据、索引元数据以及待同步的写入队列。在 Chrome 开发者工具的 Application 面板中,可以看到对应的 IndexedDB 数据库及其占用的存储空间。需要注意的是,IndexedDB 本身受浏览器配额管理,Firestore 的 40MB 限制是在这个配额内部自己的回收阈值。
这 40MB 指的是 Firestore 本地缓存的总容量上限,包括已同步的只读数据、查询结果、元数据以及尚未同步的挂起写入。它不是一个单个文档的大小限制,也不是一个绝对的硬限制。当缓存达到这个阈值后,Firestore 会启动内部清理流程,移除最久未使用的数据。对于 Realtime Database,则使用另一套独立的离线缓存机制,默认大小为 10MB,与 Firestore 的 40MB 不可混用。
二、调整缓存大小限制的 API 与注意事项
移动端调整缓存大小主要通过 setCacheSizeBytes 方法。以 Android Kotlin 为例,可以在构建 Firestore 设置时指定字节数:
val settings = firestoreSettings {
setCacheSizeBytes(100L * 1024L * 1024L) // 100MB
}
db.firestoreSettings = settings
上述代码将缓存上限设置为 100MB。如果希望取消限制,可以使用 Firestore.CACHE_SIZE_UNLIMITED 常量。不过这个设置必须在数据库实例被使用之前完成,如果已经执行过读写操作,可能需要应用重启才能生效。iOS 和 Android 的 API 基本相同,均接收 Long 类型的字节数。
Web SDK 在 v9 及以上版本中,采用了模块化 API。启用带自定义缓存大小的持久化,需要在 initializeFirestore 时传入 persistentLocalCache 配置:
import { initializeFirestore, persistentLocalCache } from "firebase/firestore";
const db = initializeFirestore(app, {
localCache: persistentLocalCache({
cacheSizeBytes: 100 * 1024 * 1024 // 100MB
})
});
Web 端同样提供了 CACHE_SIZE_UNLIMITED 常量。调整缓存大小并非没有代价。更大的缓存意味着更多的磁盘占用,在低端手机上可能影响系统存储空间。Web 端虽然 IndexedDB 本身由浏览器分配配额,但 Firestore 自己的 40MB 阈值会先触发回收,调大到 100MB 后可以缓存更多数据,但也会增加浏览器存储压力。如果设置为无限制,应用不断写入文档,最终可能耗尽浏览器可用配额,导致客户端错误。
三、缓存写满时的数据淘汰行为与同步风险
Firestore 在缓存达到上限后,会按照最近最少使用(LRU)的近似策略移除文档。它倾向于删除最久没有被访问的缓存数据,包括已同步的只读快照和尚未同步的挂起写入。关键点在于:未同步的写入并不享有特殊的保留优先级,一旦被逐出,本地缓存的写操作就会丢失。这是很多离线优先应用在长时间断网后出现数据“消失”的根因。
设想一个典型场景:用户在飞机上离线编辑了 60 条记录,每条记录平均 1MB,缓存很快超过 40MB。最早编辑的一些记录可能被淘汰,但界面仍然显示它们的状态,因为本地读取可以继续工作。航班落地恢复网络后,应用只同步了缓存里剩下的记录,被淘汰的那几条永远没有到达服务器。用户几乎没有感知,直到重新查询时才可能发现数据回退。因此,单纯依赖 Firestore 默认缓存大小来支撑大量离线写入是非常危险的。
Firestore 没有直接暴露缓存水位的 API,但可以通过监听写入失败事件或使用 waitForPendingWrites() 检查挂起状态。在移动端可通过计算数据库文件大小粗略估算;Web 端可以使用 navigator.storage.estimate() 获得整个源的存储用量,从而推测 IndexedDB 配额使用情况:
if (navigator.storage && navigator.storage.estimate) {
const estimate = await navigator.storage.estimate();
console.log(`已使用 ${estimate.usage} 字节,配额 ${estimate.quota} 字节`);
}
四、合理设置离线缓存大小的实践建议
根据业务数据特征计算所需缓存是第一步。例如一个文档平均 5KB,离线需要访问 2000 个文档,那么理论上需要至少 10MB,考虑索引和元数据后建议设 20-30MB。不要盲目设置成无限制,尤其当用户生成大量图片或长文本时。可以先在开发阶段用较小的缓存上限做压力测试,观察数据淘汰行为。
使用数据分层与查询限制可以显著降低缓存压力。不要将所有历史数据缓存到本地,可以只缓存最近活跃项目、最近 N 天记录,通过查询限制结果集。删除文档时注意本地缓存不会立即清理,需借助 clearPersistence() 或重启应用。注意 clearPersistence() 会删除所有缓存和挂起的写入,必须在没有待处理写入时调用,否则会拒绝执行。
最后,上线后要结合崩溃日志或自定义日志记录缓存相关错误,Web 应用还可以定期调用存储估计算法,在 UI 中提示用户清理离线数据。下面是一个清空 Firestore 缓存的示例:
db.clearPersistence().then(() => {
console.log("Firestore 离线缓存已清空");
}).catch(err => {
console.error("清空缓存失败,可能有挂起的写入", err);
});
通过合理规划缓存容量、限制离线写入量并定期监控,可以在离线体验和磁盘占用之间找到平衡,避免出现难以排查的数据同步丢失问题。
Firebase离线持久化离线缓存大小IndexedDB修改时间:2026-09-26 06:08:25