Web Storage

在浏览器中存储数据有许多不同的选项。哪种方式最能满足您的需求?

出门在外时互联网连接会不稳定或无法连接,因此 离线支持和可靠的性能是 渐进式 Web 应用。即便是在完美的无线环境下 明智地使用缓存和其他存储技术 显著改善用户体验。您可以通过多种方式 您的静态应用资源(HTML、JavaScript、CSS、图片等),以及 数据(用户数据、新闻报道等)。但以下哪个是最佳解决方案?方法 您能存储多少数据?如何防止它被逐出?

我应该使用什么?

以下是有关存储资源的一般建议:

所有新型浏览器都支持 IndexedDB 和 Cache Storage API。 它们都是异步的,不会阻塞主线程。它们是 可从 window 对象、Web Worker 和 Service Worker 访问, 因此可以轻松在代码中的任何位置使用它们。

其他存储机制如何?

浏览器中还有其他几种存储机制, 使用有限,并且可能会导致严重的性能问题。

SessionStorage 特定于标签页,其范围限定为 每个标签页的生命周期它可能适合存储少量会话 特定信息,例如 IndexedDB 键。它应该与 请谨慎操作,因为它是同步的,并且会阻塞主线程。时间是 文件大小不得超过 5MB,且只能包含字符串。由于是标签专用 无法从 Web Worker 或 Service Worker 进行访问。

应避免使用 LocalStorage,因为它是同步的 并且会阻塞主线程文件大小不得超过 5MB, 字符串。无法从 Web Worker 或服务访问 LocalStorage worker。

Cookie 有其用途,但不应用于存储。 Cookie 随每个 HTTP 请求一起发送,因此除了 少量数据会显著增加每个网络请求的大小。 它们是同步的,并且无法从 Web Worker 进行访问。点赞 LocalStorage 和 SessionStorage,Cookie 仅限于字符串。

File System API 和 FileWriter API 提供了 在沙盒文件系统中读取和写入文件。虽然是异步的 那么我们不建议您这样做 仅适用于基于 Chromium 的浏览器

File System Access API的设计初衷就是 让用户能够轻松读取和编辑本地文件系统中的文件。用户 必须先授予权限,然后页面才能读取或写入任何本地文件;以及 权限在会话间不会持久保存。

应使用 WebSQL,且应将现有用法迁移到 IndexedDB。几乎所有主要应用都不再提供支持 。W3C 于 2010 年停止了维护 Web SQL 规范, 且未计划进一步更新。

不应使用应用缓存,而应根据现有用量 迁移到 Service Worker 和 Cache API。过去 已弃用,并且我们将不再支持 未来。

我可以存储多少内容?

简而言之,很多,至少有几百 MB, 数百 GB 或更多。各个浏览器的实施方法会有所不同 可用存储空间通常取决于 设备。

  • Chrome 最多允许浏览器使用总磁盘空间的 80%。来源可以 最多可使用总磁盘空间的 60%。您可以使用 StorageManager API 来确定可用的最大配额。其他基于 Chromium 的 可能有所不同
    • 在无痕模式下,Chrome 会减少源服务器可以使用的存储空间 约为总磁盘空间的 5%。
    • 如果用户启用了“在关闭所有 Cookie 时清除 Cookie 和网站数据” 窗口”存储配额将大大减少 大小上限约为 300MB。
    • 请参阅 PR #3896 有关 Chrome 实现的详情。
  • Internet Explorer 10 及更高版本最多可存储 250MB,并会提示 用量超过 10MB 时向用户显示。
  • Firefox 最多允许浏览器使用 50% 的可用磁盘空间。一个 eTLD+1 群组(例如,example.comwww.example.comfoo.bar.example.com最多可能会使用 2GB。您可以使用 StorageManager API 来确定剩余空间量 可用。
  • Safari(桌面版和移动版)似乎允许大约 1GB 空间。当 Safari 会提示用户,并将上限提高到 200MB 增量。我找不到任何与此相关的官方文档。
    • 在移动版 Safari 的主屏幕上添加 PWA 时, 创建新的存储容器时,PWA 之间不会共享任何内容 和移动版 Safari 浏览器当已安装的 PWA 达到配额后, 似乎无法请求额外的存储空间。

过去,如果网站存储的数据量超过特定阈值, 浏览器会提示用户授予使用更多数据的权限。对于 例如,如果源占用的空间超过 50MB,浏览器就会提示用户 允许其存储最多 100MB 的数据,然后以 50MB 的增量再次询问。

目前,大多数现代浏览器都不会提示用户,而是允许网站 最多使用分配给它的配额Safari 例外 在超出存储配额时发出提示,请求增加 分配的配额。如果来源 尝试写入数据的次数超出其分配的配额,则会进一步尝试写入数据 都将失败。

如何查看可用存储空间?

许多浏览器中,您可以使用 StorageManager API,用于确定 以及它占用了多少存储空间它会报告 IndexedDB 和 Cache API 使用的字节数, 以计算剩余的大致可用存储空间。

if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}

StorageManager 尚未在所有浏览器中implemented,因此您可以 必须先进行特征检测,然后才能使用。即使可用,您必须 仍会捕获超出配额的错误(见下文)。在某些情况下, 超过可用配额的实际可用存储空间。

检查

在开发过程中,您可以使用浏览器的开发者工具来检查 不同存储类型,并轻松清除所有存储的数据。

Chrome 88 中新增了一项功能,可让您覆盖网站的存储空间 配额。借助此功能,您可以模拟 并测试应用在磁盘可用性较低的情况下的行为 场景。依次进入应用存储,启用 模拟自定义存储空间配额复选框,然后输入任意有效数字以 模拟存储空间配额

开发者工具 Storage 窗格。

在撰写本文时,我编写了一个简单的工具, 尽可能快速地使用存储空间这是一种既快速又简单的 尝试不同的存储机制,看看 您的全部配额

如何处理超出配额的问题?

如果超出配额,您应该怎么做?最重要的是,您应该 始终捕获并处理写入错误,无论是 QuotaExceededError 还是 别的什么。然后,根据您的应用设计,决定如何处理它。 例如,删除长期无人访问的内容 或为用户提供一种方式来选择要删除的内容。

IndexedDB 和 Cache API 都会抛出名为DOMError 在您超出可用配额时QuotaExceededError

IndexedDB

如果源站已超出其配额,尝试写入 IndexedDB 会 失败。系统将调用事务的 onabort() 处理程序,并传递一个事件。 该事件的错误属性中将包含 DOMException。检查 错误 name 将返回 QuotaExceededError

const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
  const error = event.target.error; // DOMException
  if (error.name == 'QuotaExceededError') {
    // Fallback code goes here
  }
};

Cache API

如果源站已超出其配额,会尝试向 Cache API 写入数据 会拒绝,并返回 QuotaExceededError DOMException

try {
  const cache = await caches.open('my-cache');
  await cache.add(new Request('/sample1.jpg'));
} catch (err) {
  if (error.name === 'QuotaExceededError') {
    // Fallback code goes here
  }
}

逐出是如何运作的?

Web 存储分为两个存储分区,即“尽力而为”和“持久性” “尽力而为”意味着浏览器无需 会干扰用户,但对于长期或关键数据而言,其持久性较差。 存储空间不足时,永久性存储空间不会自动清除。用户 需要手动清除此存储空间(通过浏览器设置)。

默认情况下,网站的数据(包括 IndexedDB、Cache API 等)归入 “尽力而为”类别,这意味着除非网站 请求的永久性存储空间,则浏览器可能会逐出 (例如当设备存储空间不足时)。

尽力逐出政策如下:

  • 基于 Chromium 的浏览器在浏览器耗尽时将开始逐出数据 先清除最近最少使用的来源中的所有网站数据, 然后下一次,直至浏览器不再超出限制。
  • Internet Explorer 10 及更高版本不会逐出数据,但会阻止来源从 这样就不用再写作了
  • 当可用磁盘可用空间已满时,Firefox 会开始逐出数据, 先清除最近最少使用的来源中的所有网站数据,然后清除 直到浏览器不再超出此限制。
  • Safari 以前不逐出数据,但最近实施了新的 7 天上限(见下文)。

从 macOS 上的 iOS 和 iPadOS 13.4 和 Safari 13.1 开始, 所有脚本可写存储(包括 IndexedDB、service)的 7 天上限 工作器注册和 Cache API。这意味着 Safari 将所有 使用 Safari 7 天后从缓存中获取的内容(如果用户没有 与网站互动此逐出政策不适用于已安装的 PWA。请参阅 WebKit 上的全面的第三方 Cookie 拦截及其他功能 博客。

额外知识点:为何对 IndexedDB 使用封装容器

IndexedDB 是一种低级别 API,在使用之前需要进行大量设置, 这在存储简单数据时特别困难。与大多数现代 基于 promise 的 API,则基于事件。如 Promise 封装容器, IndexedDB 的 idb 隐藏了一些强大的功能,但 重要的是,隐藏复杂的机制(如事务、架构版本控制) IndexedDB 库自带的库。

总结

限制存储空间、提示用户存储更多 更多数据。网站可以有效存储其所有资源和数据 运行。借助 StorageManager API,您可以 确定您可用的配额和用量。通过 永久性存储空间,除非用户将其移除,否则 可以防止资源被逐出

其他资源

谢谢

特别感谢 Jarryd Goodman、Phil Walton、Eiji Kitamura、Daniel Murphy、 Darwin Huang、Josh Bell、Marijn Kruisselbrink 和 Victor Costan 点评 本文。感谢北村英二、Addy Osmani 和 Marc Cohen, 所依据的原创文章Eiji 编写了一款有用的工具 浏览器存储空间滥用用户 当前行为它可让您存储尽可能多的数据,并查看 存储空间上限感谢进行挖掘的 Francois Beaufort 来了解其存储空间限制

主打图片由 Guillaume Bolduc 制作 取消启动