跳转到内容

存储 · API

StorageManager.persist() 与 persisted()

发布于

navigator.storage.persist() 请求浏览器把该源的存储桶标记为持久化,从而让 Cache Storage、IndexedDB、OPFS 和 Service Worker 注册免于存储压力下的自动逐出。navigator.storage.persisted() 报告这个标记是否已设置。两者都不改变配额,只改变浏览器能否在用户没有要求的情况下清除数据。

navigator.storage.persist()
navigator.storage.persisted()

两者都返回 Promise<boolean>。persist() 在调用后存储桶处于持久化模式时兑现为 true(不论是刚授予还是原本就是),浏览器拒绝时为 false。persisted() 只读取当前模式。persist() 暴露在 Window 上、worker 内没有;persisted() 两处都有(BCD api.StorageManager.persist:Chrome 55、Firefox 57、Safari 15.2)。两者都要求安全上下文。

无。

异常 触发条件
TypeError 浏览器无法为该源获取存储架:源是不透明源(没有 allow-same-origin 的沙箱 <iframe>,部分引擎中的 data: 或 file: 文档),或用户已为该站点禁用存储。Promise 被拒绝。

被拒绝不是异常。浏览器认为站点尚未赢得持久化资格时,persist() 兑现为 false,源仍保持尽力而为模式。

Storage 标准把决定权留给浏览器,三个引擎走了三条不同的路(Storage quotas and eviction criteria,developer.mozilla.org)。

引擎 调用 persist() 时的行为 影响决定的因素
Chromium(Chrome、Edge) 不弹提示。请求被静默授予或拒绝,被拒后可以稍后再次申请(Persistent storage,web.dev)。 站点参与度得分、站点是否已安装或加入书签、是否已授予 notifications 权限。
Firefox 显示权限气泡并等待用户。 用户的点击。Firefox 会按站点记住拒绝。
WebKit(Safari 15.2+) 不弹提示;根据用户与站点的交互历史自动授予或拒绝。 此前与该源的第一方交互。

Chromium 的授予取决于参与度,因此首次访问首屏时的调用最可能返回 false。在用户安装应用、开启通知或完成一次有意义的操作之后再调用,不改代码也能提高成功率。

脚本没有撤销持久化的 API。用户通过站点设置(Chrome:chrome://settings/content/siteDetails?site=<源>;Firefox:页面信息里的权限一节)或清除站点数据来撤销。

示例把「申请」(参与度信号之后做一次)和「读取」(每次启动)分开,这正是两个方法的预期用法。

把申请绑定到用户做出「这个站点有价值」动作的时刻,并根据布尔值行动而不是假设成功。下面的例子在安装成功或通知权限被授予之后运行。

async function requestDurableStorage() {
if (await navigator.storage.persisted()) return true;
const granted = await navigator.storage.persist();
if (!granted) {
console.info('存储仍为尽力而为模式;被逐出的排队任务会重新同步。');
}
return granted;
}

返回 false 时应用照常工作:写入 IndexedDB 或 Cache Storage 的数据在出现存储压力之前都在,Safari 则是在七天浏览器使用天数内无交互之前都在(见逐出与尽力而为存储)。把同步层设计成「缺失的记录重新拉取或重新推导」,而不是当作数据损坏。

persisted() 是廉价的读取;每次启动都调用,不要缓存结果,因为用户可能在两次访问之间撤销持久化,Chromium 也可能在参与度上升后授予之前拒绝过的申请。

async function describeStorageMode() {
const persistent = await navigator.storage.persisted();
return persistent
? '离线数据不会被自动清除。'
: '设备空间不足时离线数据可能被清除。';
}

把这句话和 StorageManager.estimate() 的用量数字放在一起,设置页就同时说明了存了多少、有多安全。

不安全源上没有 navigator.storage,早于 Chrome 55、Firefox 57、Safari 15.2 的浏览器也没有。把方法缺失当作尽力而为存储处理。

async function ensurePersistence() {
if (!('storage' in navigator) || typeof navigator.storage.persist !== 'function') {
return false; // 不支持:按尽力而为存储处理
}
try {
return await navigator.storage.persist();
} catch (err) {
if (err.name === 'TypeError') return false; // 不透明源或存储被禁用
throw err;
}
}

函数对「不支持」「被拒绝」「存储被禁用」返回同一个 false,这是有意为之:调用方只有一条回退路径,三种情况下都一样。

规范

规范状态
无。