作者:半年的半年
来源:SegmentFault 思否
前言
今天我们来讲一讲 Web 存储有几种机制,并弄清楚什么是临时存储,什么是持久存储。
你可能不知道的是:我们平常口中所说的持久存储 localStorage 很多时候其实是系统级别的“临时存储”。
正文
IndexedDB
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_APIIndexed DB 的操作是异步的,不会阻塞主线程的执行,可以在 window、web workers、service workers 环境中使用。
IndexedDB 是基于文件存储的,API 较为复杂,包含 v1 v2 的差异,建议通过类库来使用,比如:Dexie.js。
Cache Storage API
https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/cache-apiCache Storage API 为缓存的 Request/Response 对象提供存储机制,常在 ServiceWorker 中应用。
异步,不会阻塞主线程的执行,可以在 window、web workers、service workers 环境中使用。
SessionStorage
https://developer.mozilla.org/en/docs/Web/API/Window/sessionStorage
同步,会阻塞主线程的执行。
一般用于储存临时性的少量的数据。
SessionStorage 是标签级别的,跟随者标签的生命周期,并且会随着标签的销毁而清空数据。
无法在 web workers、service workers 环境中使用。
它只能储存字符串,大小限制大约为 5MB。
LocalStorage
https://developer.mozilla.org/en/docs/Web/API/Window/sessionStorage同步,会阻塞主线程的执行。
无法在 web workers、service workers 环境中使用。
它只能储存字符串,大小限制大约为 5MB。
Cookies
https://developer.mozilla.org/en-US/docs/Web/HTTP/CookiesCookies 有它的用途,但不适用于储存数据。
Cookie 会在每次 HTTP 请求的时候携带在请求头中,大体积的 Cookies 会显著增加 HTTP 请求的负担。
Cookies 读写是同步的,只能储存字符串,并且无法在 web workers 环境中使用。
File System API
https://developer.mozilla.org/en-US/docs/Web/API/File_and_Directory_Entries_API/Introduction
File System API 和 FileWriter API 提供读取或写入文件到沙箱中(Sandboxed file system)。
它是异步的,不推荐使用,因为 File System API 只能在 Chromium 内核中使用。
File System Access API
https://web.dev/file-system-access/
File System Access API 设计用于便捷得读取和编辑本地文件。
但在读取或写入本地文件的时候,需要获得用户授权,并且授权状态无法持久化记录。
Application Cache
Application Cache 已被弃用,不建议使用。
建议迁移至 service workers 或 Cache API。
Storage 可以使用多少磁盘空间?
- Chrome 允许使用 80% 的硬盘空间,单一的源(域名)可以使用 60% 的硬盘空间,可以通过 StorageManager API 检测最大的硬盘空间限额,其他基于 Chromium 内核的浏览器有不一样的限制,可能会允许使用更多的硬盘空间,查看更多实现 PR #3896
- Internet Explorer 10(IE 10)及以上,最多可以储存 250MB,并在超过 10MB 的时候会提示用户
- Firefox 允许使用 50% 的空闲硬盘空间,单个一级域名最多可以使用 2GB 硬盘空间,可以通过 StorageManager API 检测最大的硬盘空间限额
- Safari 允许使用 1GB,当达到 1GB 的时候会提示用户(该数据可能不准确,没有找到 Safari 官方文档)
如何检测储存空间是否可用?
在大多数浏览器中,可以通过 StorageManager 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.`);
}
// quota data
{
"quota": 299977904946,
"usage": 27154039,
"usageDetails": {
"caches": 26813093,
"indexedDB": 305864,
"serviceWorkerRegistrations": 35082
}
}
注意:
- 并不是所有浏览器都实现了,因此使用之前需要先判断兼容性
- 需要捕获并处理超过配额限额的错误
IndexedDB 超限处理
indexedDB 超限将会执行 onabort 回调,并抛出一个 DOMException 错误,需要处理它的 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 超限处理
抛出一个 Promise Rejection,QuotaExceededError 错误对象,需要处理它的 QuotaExceededError 异常。
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 Storage 分为两种储存模式,分别是:临时存储 Best Effort 和持久存储 Persistent。 默认情况下网站数据(包括 IndexedDB, Cache API, LocalStorage 等)都储存在临时存储 Best Effort 中,会在存储空间不足的时候被浏览器清除掉。 各个浏览器回收存储空间的差异:- Chrome 当浏览器存储空间不足时,会优先清除最近最少使用的数据,逐个清除,直至不再超限
- IE 10+ 不会自动清除数据,但会阻止站点继续写入数据
- Firefox 当磁盘空间充满时,会优先清除最近最少使用的数据,逐个清除,直至不再超限
- Safari(iOS、iPadOS、MacOS) 会自动清除超过 7 天以上的数据,但不会清除“已添加至主屏幕”的网站和“PWA”网站
申请和查看持久存储 Persistent Storage
申请持久存储 Persistent Storage:// Request persistent storage for site
if (navigator.storage && navigator.storage.persist) {
const isPersisted = await navigator.storage.persist();
console.log(`Persisted storage granted: ${isPersisted}`);
}
查看
持久存储 Persistent Storage 授权状态:
// Check if site's storage has been marked as persistent
if (navigator.storage && navigator.storage.persist) {
const isPersisted = await navigator.storage.persisted();
console.log(`Persisted storage granted: ${isPersisted}`);
}
各个浏览器申请持久存储 Persistent Storage 的差异:
- 在 Chrome 55 以后,申请持久存储只需要满足以下任一条件,即可自动获得持久存储权限,无需用户确认:
- 该站点已添加书签, 并且用户的书签数小于等于5个
- 站点有很高的"site engagement",通过这个命令可以查看: chrome://site-engagement/
- 站点已添加到主屏幕
- 站点启用了push通知功能
- 在 Firefox 中,会提示用户授权
- 打开 https://baidu.com,打开控制台输入 await navigator.storage.persist(),返回 true
- 打开 https://wy.guahao.com,打开控制台输入 await navigator.storage.persist(),返回 false
参考文献
- 《Storage for the web》
- 《Persistent storage》
- END -