簡介
對於現代瀏覽器來說,為了提升效率和處理更加復雜的客戶端操作,通常都需要將數據存儲在客戶端,也就是本地磁盤上。那么這個存儲有沒有什么限制?如果數據存滿了之后,如何進行數據的淘汰和置換?
一起來看看吧。
常用的客戶端存儲方式
客戶的存儲方式都有哪些呢?
我們看一下比較常用的幾種方式:
- IndexedDB
- asm.js caching
- Cache API
- Cookies
- web storage
當然還有其他的客戶端存儲類型,比如AppCache(已經被廢棄),File System API(非標准的API)等。
data storage的類型
通常來說,data storage有兩種方式,一種是永久性的,這種情況下通常數據會存儲比較長的時間,除非用戶選擇清除(比如清除瀏覽器緩存),否則數據將會永久保存。
一種是臨時存儲,這種情況下,數據會存儲有限的時間。數據存儲的容量是有限的,在有限的數據容量空間,我們需要一些特定的數據逐出算法來保證有效的數據不會被覆蓋。
逐出策略
在使用臨時存儲模式時,我們通常使用的逐出策略是LRU。
當到達存儲的限額的時候,將會查找所有當前未使用的origin,然后根據最后訪問時間對他們進行排序。然后刪除最近最少使用的origin信息。
Storage API
為了統一和規范這些客戶端的操作API,於是引入了Storage API,通過Storage API我們可以查看可用存儲空間大小,已使用的空間大小,甚至可以控制在用戶數據清除的時候是否需要提醒用戶。
注意Storage API只適用於HTTPS的情況,並且只是部分瀏覽器支持。
為了對不同源的數據進行管理,引入了storage units(也叫做box)的概念,對於每一個源來說,都有一個storage units(Box)。
不同的storage units里面可以存儲不同類型的數據。
上圖中Origin 1中既有Web Storage,也有IndexedDB的存儲,因為並沒有達到Storage的最大值,所以還留有一定的空余空間。
Origin 2中還沒有開始存儲任何數據,所以都是空的。
Origin 3中被indexedDB存滿了,沒有任何空余空間。
為了方便管理box有兩種模式,一種叫best-effort,一種叫persistent。
best-effort模式是指瀏覽器會盡最大努力去保留數據,但是當存儲空間用完的時候,瀏覽器並不會提醒用戶可能對存儲空間的清理操作。
persistent模式將會盡可能長時間的保存用戶的數據,如果同時有best-effort和persistent模式的話,當存儲空間不足的時候,將會首先清除best-effort box。如果一定要清除persistent box,將會通知相應的用戶。
Storage API指的就是StorageManager,它有三個非常重要的方法estimate,persist和persisted,我們看下他們的瀏覽器兼容性:
基本上,現代瀏覽器都支持StorageManager和它的三個方法。
下面我們分別來看一下他們的使用。
StorageManager是一個接口,用來管理存儲的權限和評估可用的空間。我們可以通過navigator.storage 或者WorkerNavigator.storage 來獲取到StorageManager。
我們看一下StorageManger的定義:
interface StorageManager {
estimate(): Promise<StorageEstimate>;
persist(): Promise<boolean>;
persisted(): Promise<boolean>;
}
estimate
estimate方法返回一個Promise,Promise中包含一個StorageEstimate對象,表示空間的使用情況和限額。
navigator.storage.estimate().then(estimate => {
// estimate.quota is the estimated quota
// estimate.usage is the estimated number of bytes used
});
我們使用estimate來查看是否有住夠的空間進行應用數據的存儲:
function retrieveNextChunk(nextChunkInfo) {
return navigator.storage.estimate().then(info => {
if (info.quota - info.usage > nextChunkInfo.size) {
return fetch(nextChunkInfo.url);
} else {
throw new Error("insufficient space to store next chunk");
}
}).then( /* … */ );
}
上面是一個estimate的使用。
persist
persist方法返回一個Promise,true表示user agent已被授權,並且box mode= persistent模式。
我們看一下persist 的使用:
if (navigator.storage && navigator.storage.persist)
navigator.storage.persist().then(function(persistent) {
if (persistent)
console.log("Storage will not be cleared except by explicit user action");
else
console.log("Storage may be cleared by the UA under storage pressure.");
});
persisted
persisted方法返回一個Promise,true表示box mode= persistent模式。
我們看一個persisted的例子:
if (navigator.storage && navigator.storage.persist)
navigator.storage.persisted().then(function(persistent) {
if (persistent)
console.log("Storage will not be cleared except by explicit user action");
else
console.log("Storage may be cleared by the UA under storage pressure.");
});
綜合使用
之前講到了,如果是persistent模式,數據的清理需要通知用戶,下面我們看一下這個判斷該怎么寫:
Promise.all([
navigator.storage.persisted(),
navigator.permissions.query({name: "persistent-storage"})
]).then(([persisted, permission]) => {
if (!persisted && permission.status == "granted") {
navigator.storage.persist().then( /* … */ );
} else if (!persisted && permission.status == "prompt") {
showPersistentStorageExplanation();
}
});
上面的例子,我們還使用到了Permissions API。通過Permissions API,我們來判斷用戶所擁有的權限。
Permissions API還是一個比較新的API,只有在Chrome 44和Firefox 43之后才支持。
我們可以通過navigator.permissions來獲取到Permissions API。
可以通過Permissions.query()來判斷是否具有相應的權限。
Permissions.query將會返回一個PermissionStatus對象,這個對象代表了三個狀態:granted,prompt和denied。
我們看一個判斷權限的應用:
function handlePermission() {
navigator.permissions.query({name:'geolocation'}).then(function(result) {
if (result.state == 'granted') {
report(result.state);
geoBtn.style.display = 'none';
} else if (result.state == 'prompt') {
report(result.state);
geoBtn.style.display = 'none';
navigator.geolocation.getCurrentPosition(revealPosition,positionDenied,geoSettings);
} else if (result.state == 'denied') {
report(result.state);
geoBtn.style.display = 'inline';
}
result.onchange = function() {
report(result.state);
}
});
}
function report(state) {
console.log('Permission ' + state);
}
handlePermission();
除了Query,我們還可以使用revoke來取消授權。
function revokePermission() {
navigator.permissions.revoke({name:'geolocation'}).then(function(result) {
report(result.state);
});
總結
Storage API是為了統一客戶端存儲標准所制定的API。還在不斷的完善之中。感興趣的朋友可以多多關注它的進展。
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/storage-api-limit/
本文來源:flydean的博客
歡迎關注我的公眾號:「程序那些事」最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!