1. 程式人生 > >Storage API簡介和儲存限制與逐出策略

Storage API簡介和儲存限制與逐出策略

[toc] # 簡介 對於現代瀏覽器來說,為了提升效率和處理更加複雜的客戶端操作,通常都需要將資料儲存在客戶端,也就是本地磁碟上。那麼這個儲存有沒有什麼限制?如果資料存滿了之後,如何進行資料的淘汰和置換? 一起來看看吧。 # 常用的客戶端儲存方式 客戶的儲存方式都有哪些呢? 我們看一下比較常用的幾種方式: * 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)。 ![](https://img-blog.csdnimg.cn/20201004232652967.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_25,color_8F8F8F,t_70) 不同的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,我們看下他們的瀏覽器相容性: ![](https://img-blog.csdnimg.cn/20201005090319501.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_25,color_8F8F8F,t_70) 基本上,現代瀏覽器都支援StorageManager和它的三個方法。 下面我們分別來看一下他們的使用。 StorageManager是一個介面,用來管理儲存的許可權和評估可用的空間。我們可以通過navigator.storage 或者WorkerNavigator.storage 來獲取到StorageManager。 我們看一下StorageManger的定義: ~~~js interface StorageManager { estimate(): Promise; persist(): Promise; persisted(): Promise; } ~~~ ## estimate estimate方法返回一個Promise,Promise中包含一個StorageEstimate物件,表示空間的使用情況和限額。 ~~~js navigator.storage.estimate().then(estimate => { // estimate.quota is the estimated quota // estimate.usage is the estimated number of bytes used }); ~~~ 我們使用estimate來檢視是否有住夠的空間進行應用資料的儲存: ~~~js 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 的使用: ~~~js 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的例子: ~~~js 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模式,資料的清理需要通知使用者,下面我們看一下這個判斷該怎麼寫: ~~~js 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。 我們看一個判斷許可權的應用: ~~~js 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來取消授權。 ~~~js function revokePermission() { navigator.permissions.revoke({name:'geolocation'}).then(function(result) { report(result.state); }); ~~~ # 總結 Storage API是為了統一客戶端儲存標準所制定的API。還在不斷的完善之中。感興趣的朋友可以多多關注它的進展。 > 本文作者:flydean程式那些事 > > 本文連結:[http://www.flydean.com/storage-api-limit/](http://www.flydean.com/storage-api-limit/) > > 本文來源:flydean的部落格 > > 歡迎關注我的公眾號:「程式那些事」最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!