存储 · 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,源仍保持尽力而为模式。
各浏览器如何决定
Section titled “各浏览器如何决定”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:页面信息里的权限一节)或清除站点数据来撤销。
示例把「申请」(参与度信号之后做一次)和「读取」(每次启动)分开,这正是两个方法的预期用法。
在参与度信号之后申请持久化
Section titled “在参与度信号之后申请持久化”把申请绑定到用户做出「这个站点有价值」动作的时刻,并根据布尔值行动而不是假设成功。下面的例子在安装成功或通知权限被授予之后运行。
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 则是在七天浏览器使用天数内无交互之前都在(见逐出与尽力而为存储)。把同步层设计成「缺失的记录重新拉取或重新推导」,而不是当作数据损坏。
在设置页里报告当前模式
Section titled “在设置页里报告当前模式”persisted() 是廉价的读取;每次启动都调用,不要缓存结果,因为用户可能在两次访问之间撤销持久化,Chromium 也可能在参与度上升后授予之前拒绝过的申请。
async function describeStorageMode() { const persistent = await navigator.storage.persisted(); return persistent ? '离线数据不会被自动清除。' : '设备空间不足时离线数据可能被清除。';}把这句话和 StorageManager.estimate() 的用量数字放在一起,设置页就同时说明了存了多少、有多安全。
检测支持并降级
Section titled “检测支持并降级”不安全源上没有 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,这是有意为之:调用方只有一条回退路径,三种情况下都一样。
- Storage: persist() method(whatwg.org)
- Persistent storage(web.dev)
- Storage quotas and eviction criteria(developer.mozilla.org)
- 逐出与尽力而为存储
- StorageManager.estimate()
- IndexedDB
规范
| 规范 | 状态 |
|---|---|
| 无。 | |