简介
一般web应用存储数据到本地有多种方式. 比如indexedDb,Cache Api, 或者localStorage. 当然, 所有的这些存储,都会占用本地机器的存储空间.
当本地的存储空间不足时, 浏览器会自动清除这些本地存储, 以获得更多可用的存储空间. 针对离线应用或者PWA, 这是非常不幸的. 可能本地的数据还没有同步到服务器, 或者应用本身就是希望提供离线访问的能力. 不过好消息是, 浏览器给我们提供了两种存储模式:
- best effort : 临时存储
- persistent: 持久化存储
默认的模式, 当然是"best effort", 存储空间不足时, 会被浏览器自动清理. 但是"persistent"模式, 浏览器不会自动清除, 需要用户手动,才能清除。
如何申请"persistent"存储模式
我们可以通过以下代码申请.
/**
* 申请持久存储.
*/
function grantPersist() {
return wrapPromise((resolve, reject) => {
if (navigator.storage && navigator.storage.persist) {
navigator.storage.persist().then(granted => {
// granted: true / false
if(granted){
console.log("持久化存储模式, 需要用户手动清除")
}else{
console.log("临时存储模式, 存储空间不足时, 浏览器会自动清除")
}
resolve(granted);
});
} else {
reject('navigator.storage.persist: 不支持');
}
});
}
是否需要用户授权?
- 在chrome 55以后, 站点满足一下任意一个条件时, 浏览器会自动授权. 无需用户确认.
- 该站点已添加书签, 并且用户的书签数小于等于5个
- 站点有很高的"site engagement". 通过这个命令可以查看: chrome://site-engagement/
- 站点已添加到主屏幕
- 站点启用了push通知功能.
除了以上几种情况, 其他的任何情况都会被自动拒绝.
- 在firefox上: 会有一个弹框, 需要用户授权.
如果查看当前的存储模式
我们可以调用"navigator.storage.persist"api来查看
/**
* 查看存储模式
*/
function checkPersisted() {
return wrapPromise((resolve, reject) => {
if (navigator.storage && navigator.storage.persisted) {
navigator.storage.persisted().then(persisted => {
if(persisted){
console.log('当前的模式是持久化的,本地存储的数据需要用户手动清除')
}esle{
console.log('当前的模式是临时的, 浏览器在空间不足时, 会自动清除本地数据')
}
resolve(persisted)
});
} else {
reject('navigator.storage.persisted 不支持');
}
});
}
能否查看到可用的存储空间和已使用的空间?
我们可以通过api来查看
/**
* 获取可使用磁盘空间和已使用的空间的信息.
*/
function estimateSpace() {
return new Promise((resolve, reject) => {
if (navigator.storage && navigator.storage.estimate) {
navigator.storage.estimate().then(estimate => {
// 原始的单位是byte. 转成MB
const ut = 1024 * 1024;
resolve({
total: estimate.quota / ut,
usage: estimate.usage / ut
});
});
} else {
reject('navigator.storage.estimate: 不支持');
}
});
}
浏览器兼容情况

demo, 完整的代码
- util.js
function wrapPromise(cb) {
return new Promise((resolve, reject) => cb(resolve, reject));
}
/**
* 用户授权。申请持久存储.
*/
function grantPersist() {
return wrapPromise((resolve, reject) => {
if (navigator.storage && navigator.storage.persist) {
navigator.storage.persist().then(granted => {
// granted: true/false
resolve(granted);
});
} else {
reject('navigator.storage.persist: the browser is not supported');
}
});
}
/**
* 查看存储模式
*/
function checkPersisted() {
return wrapPromise((resolve, reject) => {
if (navigator.storage && navigator.storage.persisted) {
navigator.storage.persisted().then(result => resolve(result));
} else {
reject('navigator.storage.persisted is not support');
}
});
}
/**
* 获取可使用磁盘空间和已使用的空间的信息.
*/
function estimateSpace() {
return new Promise((resolve, reject) => {
if (navigator.storage && navigator.storage.estimate) {
navigator.storage.estimate().then(estimate => {
// 原始的单位是byte. 转成MB
const ut = 1024 * 1024;
resolve({
total: estimate.quota / ut,
usage: estimate.usage / ut
});
});
} else {
reject('navigator.storage.estimate: the browser is not supported');
}
});
}
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="./util.js"></script>
</head>
<body>
<button id="btn">用户授权</button>
<h1>浏览器存储信息</h1>
<h1 id="diskInfo"></h1>
<hr />
<h1>当前的存储模式是:</h1>
<h1 id="persistInfo"></h1>
<script>
// 检查浏览器的存储模式.
function getPersisted() {
checkPersisted().then(
persisted => {
document.querySelector('#persistInfo').innerHTML = persisted
? '持久'
: '临时';
},
error => {
document.querySelector('#persistInfo').innerHTML = error;
}
);
}
// 申请持久化存储权限.
function applyPersist() {
grantPersist().then(
result => {
getPersisted();
},
error => {
document.querySelector('#persistInfo').innerHTML = error;
}
);
}
// 获取可使用磁盘空间和已使用的空间的信息
function checkStorageSpace() {
estimateSpace().then(
data => {
const { total, usage } = data;
document.querySelector('#diskInfo').innerHTML = `总大小: ${(
total / 1024
).toFixed(4)}GB, 已使用${(usage / 1024).toFixed(4)}GB`;
},
error => {
document.querySelector('#diskInfo').innerHTML = error;
}
);
}
function init() {
checkStorageSpace();
getPersisted();
document.querySelector('#btn').onclick = function() {
applyPersist();
};
}
window.onload = init;
</script>
</body>
</html>
- 应用后的截图
