天天看點

Storage API簡介和存儲限制與逐出政策簡介常用的用戶端存儲方式data storage的類型逐出政策Storage API總結

簡介

對于現代浏覽器來說,為了提升效率和處理更加複雜的用戶端操作,通常都需要将資料存儲在用戶端,也就是本地磁盤上。那麼這個存儲有沒有什麼限制?如果資料存滿了之後,如何進行資料的淘汰和置換?

一起來看看吧。

常用的用戶端存儲方式

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

我們看一下比較常用的幾種方式:

  • 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 API簡介和存儲限制與逐出政策簡介常用的用戶端存儲方式data storage的類型逐出政策Storage API總結

不同的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,我們看下他們的浏覽器相容性:

Storage API簡介和存儲限制與逐出政策簡介常用的用戶端存儲方式data storage的類型逐出政策Storage API總結

基本上,現代浏覽器都支援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的部落格

歡迎關注我的公衆号:「程式那些事」最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

繼續閱讀