并非所有存储空间都是一样的:引入 Storage 存储分区

Storage Standard 定义了用于永久性存储空间和配额估算的 API,以及平台存储架构。我们将推出一个 API,使在内存压力非常大的情况下进行的永久性存储空间逐出变得更加可预测。从 Chromium 122 开始提供。

存储标准可以解决什么问题?

传统上,当用户用尽其设备上的存储空间时,使用 IndexedDB 或 localStorage 等 API 存储的数据会丢失,而用户无法干预。要使存储空间持久保留,一种方式是调用 StorageManager 接口的 persist() 方法。它同时向最终用户请求权限,并在获得许可后将存储空间更改为永久存储空间:

const persisted = await navigator.storage.persist();
if (persisted) {
  /* Storage will not be cleared except by explicit user action. */
}

这种请求保留存储空间的方法要么全部要么什么也不做。因此,没有办法表达更精细的持久性需求。它们都是一个存储分区。

Storage Buckets API

Storage Buckets API 的核心理念是,允许网站创建多个存储分区,浏览器可以在其中选择删除每个存储分区,而与其他存储分区无关。这样,开发者可以指定逐出优先级,确保最有价值的数据不会被删除。

使用场景示例

为了说明存储分区的适用情况,我们假设有一个电子邮件应用。如果应用丢失了用户未发送且仅存在于客户端上的草稿,那么情况会非常糟糕。相比之下,如果将电子邮件存储在服务器上,当浏览器的存储压力很大时,用户可能会同意将一些最早的收件箱电子邮件从客户端中移除。

“电子邮件”应用界面
为收件箱和草稿设置单独的存储分区的电子邮件应用。(仅作说明之用,并不一定反映 Gmail 的运作方式。)

使用 Storage Buckets API

创建新的存储分区

可以使用 StorageBucketManager 接口中的 open() 方法创建新的存储分区。

// Create a storage bucket for emails that are synchronized with the
// server.
const inboxBucket = await navigator.storageBuckets.open('inbox');

创建持久保留的新存储分区

为确保存储分区得到持久保留,您可以将 durabilitypersisted 选项参数传递给 open() 方法:

  • persisted 决定存储分区是否应保留。允许的值为 false(默认)或 true
  • durability 可向浏览器提供提示,帮助浏览器在断电时降低写入性能,同时降低数据丢失风险。允许的值为 'relaxed'(默认)或 'strict'

    • 'strict' 个存储分区会尝试最大限度地降低因电源故障而导致数据丢失的风险。这可能会降低性能,这意味着,写入操作可能需要更长时间才能完成,可能会影响整体系统性能,消耗更多电池电量,并可能更快地耗尽存储设备。
    • 当断电发生时,'relaxed' 存储分区可能会“忘记”过去几秒内完成的写入操作。反过来,将数据写入这些存储分区可能具有更好的性能特征,并且可能延长电池充电时间,并可能导致存储设备生命周期更长。此外,电源故障不会导致数据损坏率高于 'strict' 存储分区。
// Create a storage bucket for email drafts that only exist on the client.
const draftsBucket = await navigator.storageBuckets.open('drafts', {
  durability: 'strict', // Or `'relaxed'`.
  persisted: true, // Or `false`.
});

从存储分区访问 Storage API

每个存储分区都与存储 API(例如 IndexedDBCache 接口或 File 接口)相关联。这些存储 API 会照常运行,只是入口点来自 StorageBucket 接口(例如 StorageBucket.indexedDB)。

const inboxDb = await new Promise(resolve => {
  const request = inboxBucket.indexedDB.open('messages');
  request.onupgradeneeded = () => { /* migration code */ };
  request.onsuccess = () => resolve(request.result);
  request.onerror = () => reject(request.error);
});

在开发者工具中调试存储分区

应用 > 存储部分检查专用树中的存储分区。

在“存储”部分启用存储分区树之前和之后。

实用资源