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

簡介

對於現代瀏覽器來講,爲了提高效率和處理更加複雜的客戶端操做,一般都須要將數據存儲在客戶端,也就是本地磁盤上。那麼這個存儲有沒有什麼限制?若是數據存滿了以後,如何進行數據的淘汰和置換?web

一塊兒來看看吧。算法

經常使用的客戶端存儲方式

客戶的存儲方式都有哪些呢?api

咱們看一下比較經常使用的幾種方式:瀏覽器

  • IndexedDB
  • asm.js caching
  • Cache API
  • Cookies
  • web storage

固然還有其餘的客戶端存儲類型,好比AppCache(已經被廢棄),File System API(非標準的API)等。緩存

data storage的類型

一般來講,data storage有兩種方式,一種是永久性的,這種狀況下一般數據會存儲比較長的時間,除非用戶選擇清除(好比清除瀏覽器緩存),不然數據將會永久保存。fetch

一種是臨時存儲,這種狀況下,數據會存儲有限的時間。數據存儲的容量是有限的,在有限的數據容量空間,咱們須要一些特定的數據逐出算法來保證有效的數據不會被覆蓋。url

逐出策略

在使用臨時存儲模式時,咱們一般使用的逐出策略是LRU。spa

當到達存儲的限額的時候,將會查找全部當前未使用的origin,而後根據最後訪問時間對他們進行排序。而後刪除最近最少使用的origin信息。code

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的博客

歡迎關注個人公衆號:「程序那些事」最通俗的解讀,最深入的乾貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

相關文章
相關標籤/搜索