網頁儲存空間

在瀏覽器中儲存資料的方法有很多種。哪種解決方案最符合您的需求?

網際網路連線可能很脆弱,甚至不存在,因此為什麼離線支援和可靠的效能是漸進式網頁應用程式中的常見功能。即使在完美的無線環境中,適當地運用快取和其他儲存技術,也能大幅提升使用者體驗。快取靜態應用程式資源 (HTML、JavaScript、CSS、圖片等) 和資料 (使用者資料、新聞報導等) 的方法有很多種。不過,何者才是最合適的解決方案?您能儲存多少資料?如何避免遭到除名?

我該使用什麼?

以下是儲存資源的通用建議:

所有新式瀏覽器都支援 IndexedDB 和 Cache Storage API。 兩者皆非同步,不會封鎖主執行緒。它們可從 window 物件、網路工作站和服務工作站存取,因此可在程式碼中的任何位置使用。

那麼其他儲存機制呢?

瀏覽器還提供其他幾種儲存機制,但這些機制的用途有限,因此可能造成重大效能問題。

SessionStorage 是分頁專用,範圍限定為分頁的生命週期。這適合用來儲存少量工作階段專屬資訊,例如 IndexedDB 索引鍵。由於這是同步性質,並且會封鎖主執行緒,因此請謹慎使用。大小限制為 5 MB 左右,而且只能包含字串。由於分頁是專屬的分頁,因此網路工作站或 Service Worker 無法存取。

請避免使用 LocalStorage,因為這是同步性質,並且會封鎖主執行緒。大小限制為 5 MB 左右,而且只能包含字串。網路工作站或服務工作站無法存取 LocalStorage。

Cookie 有其用途,但不應用於儲存。每個 HTTP 要求都會傳送 Cookie,因此如果儲存的資料量超過少量資料,每項網路要求的大小都會大幅增加。這些變數為同步性質,且無法透過網路工作處理。如同 LocalStorage 和 SessionStorage,Cookie 只適用於字串。

File System API 和 FileWriter API 提供在採用沙箱機制的檔案系統中讀取及寫入檔案的方法。雖然非同步是非同步的,但由於只能在以 Chromium 為基礎的瀏覽器中使用,因此不建議使用。

File System Access API 可讓使用者輕鬆讀取及編輯本機檔案系統中的檔案。使用者必須先授予權限,網頁才能讀取或寫入任何本機檔案,且系統不會跨工作階段保留權限。

我們不應使用 WebSQL,並將現有用量遷移至索引資料庫。幾乎所有主要瀏覽器都已停止支援。W3C 於 2010 年停止維持 Web SQL 規格,規劃後續更新事宜。

請勿使用應用程式快取,現有使用情形應遷移至服務工作站和 Cache API。此工具已淘汰,未來也將從瀏覽器中移除。

我可以儲存多少商品?

簡單來說,至少會有數百 MB 或幾百 GB 以上。瀏覽器實作方式不盡相同,但可用的儲存空間量通常取決於裝置可用的儲存空間大小。

  • Chrome 允許瀏覽器使用最多 80% 的磁碟空間。來源最多可使用總磁碟空間的 60%。您可以使用 StorageManager API 來決定可用的配額上限。其他以 Chromium 為基礎的瀏覽器可能有所不同。
    • 在無痕模式中,Chrome 會將來源可使用的儲存空間量減少約佔總磁碟空間的 5%。
    • 如果使用者已在 Chrome 中啟用「關閉所有視窗時清除 Cookie 和網站資料」,儲存空間配額會大幅降低至約 300 MB。
    • 如要進一步瞭解 Chrome 的實作方式,請參閱 PR #3896
  • Internet Explorer 10 及以上版本最多可以儲存 250 MB,而且會在使用量超過 10 MB 時提示使用者。
  • Firefox 允許瀏覽器使用高達 50% 的可用磁碟空間。eTLD+1 群組 (例如example.comwww.example.comfoo.bar.example.com) 最多可使用 2 GB。您可以使用 StorageManager API 確定有多少可用的空間。
  • Safari (電腦版和行動版) 似乎支援約 1 GB。達到上限時,Safari 會提示使用者,將上限遞增 200 MB。我們找不到任何正式文件。
    • 如果 PWA 新增至行動版 Safari 主畫面,將建立新的儲存空間容器,且 PWA 和行動版 Safari 不會共用任何項目。如果已安裝的 PWA 達到配額上限,就似乎就無法要求額外儲存空間。

過去,如果網站儲存的資料量超過特定閾值,瀏覽器會提示使用者授予使用更多資料的權限。舉例來說,如果來源用量超過 50 MB,瀏覽器就會提示使用者允許儲存 100 MB 以下的資料,並在 50 MB 時再次要求數量。

現在,大多數新式瀏覽器不會向使用者顯示提示,而且會允許網站使用其分配的配額。Safari 是例外狀況,會在超過儲存空間配額時提示您要求提高分配的配額。如果來源嘗試使用超過分配的配額,則後續寫入資料的作業將會失敗。

如何查看可用的儲存空間容量?

許多瀏覽器中,您可以使用 StorageManager API 確定來源可用的儲存空間量,以及來源的儲存空間使用量。它會回報 IndexedDB 和 Cache API 使用的位元組總數,並能夠計算大約剩餘的可用儲存空間。

if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}

StorageManager 尚未在所有瀏覽器中實作,因此您必須先將其功能偵測才能使用。即使可以使用配額,您還是必須處理超出配額的錯誤 (請見下方說明)。在某些情況下,可用配額可能會超過實際可用的儲存空間容量。

檢查

在開發期間,您可以使用瀏覽器的開發人員工具檢查不同的儲存空間類型,並輕鬆清除所有儲存的資料。

Chrome 第 88 版新增了一項功能,可讓您覆寫「儲存空間窗格」的網站儲存空間配額。這項功能可讓您在磁碟可用性低的情況下模擬各種裝置,並測試應用程式的行為。依序前往「Application」和「Storage」,啟用「Simulate custom storage 配額」核取方塊,然後輸入任何有效的數字來模擬儲存空間配額。

開發人員工具「儲存空間」窗格。

在本文中,我編寫了一項簡易工具,希望能盡快使用最多儲存空間。因此,您可以輕鬆快速地測試不同的儲存空間機制,並瞭解用盡配額時會發生什麼情況。

如何處理超出配額的問題?

超出配額時,您該怎麼做?最重要的是,建議您一律擷取並處理寫入錯誤,無論是 QuotaExceededError 還是其他情況都一樣。然後根據應用程式設計,決定處理方式。例如,您可以刪除長時間未存取的內容、根據大小移除資料,或提供使用者選擇要刪除的方法。

如果您超出可用的配額,IndexedDB 和 Cache API 都會擲回名為 QuotaExceededErrorDOMError

IndexedDB

如果來源超出配額,寫入 IndexedDB 就會失敗。系統會呼叫交易的 onabort() 處理常式,並傳遞事件。事件會在錯誤屬性中包含 DOMException。檢查錯誤 name 會傳回 QuotaExceededError

const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
  const error = event.target.error; // DOMException
  if (error.name == 'QuotaExceededError') {
    // Fallback code goes here
  }
};

快取 API

如果來源超出配額,當系統嘗試寫入 Cache API 時,系統會傳回 QuotaExceededError DOMException

try {
  const cache = await caches.open('my-cache');
  await cache.add(new Request('/sample1.jpg'));
} catch (err) {
  if (error.name === 'QuotaExceededError') {
    // Fallback code goes here
  }
}

如何除名?

網路儲存空間可分為「最佳工作」和「永久」這兩個值區。 最理想情況下,瀏覽器可以在不干擾使用者的情況下清除儲存空間,但對長期或重要資料的耐用性較低。儲存空間不足時,系統不會自動清除永久儲存空間。使用者必須透過瀏覽器設定手動清除這個儲存空間。

根據預設,網站的資料 (包括 IndexedDB、Cache API 等) 屬於最佳設定類別,這表示除非網站已要求永久儲存空間,否則瀏覽器可能會自行斟酌移除網站資料 (例如裝置儲存空間不足時)。

建議的移除政策如下:

  • 以 Chromium 為基礎的瀏覽器會在瀏覽器空間不足時開始剔除資料,先清除最近使用次數最少的來源中的所有網站資料,再清除下一個來源的所有網站資料,直到瀏覽器不再超過限制為止。
  • Internet Explorer 10 以上版本不會剔除資料,但會阻礙來源寫入。
  • 可用磁碟空間達到上限後,Firefox 就會開始清除資料,先從最近使用的最少來源清除所有網站資料,直到瀏覽器不再超過限制為止。
  • Safari 先前並未收回資料,但最近已針對所有可寫入的儲存空間,全面套用新的七天上限 (詳見下文)。

從 iOS 和 iPadOS 13.4 和 macOS 上的 Safari 13.1 開始,所有可寫入指令碼的儲存空間都會有七天上限,包括 IndexedDB、服務工作站註冊和 Cache API。這表示如果使用者未與網站互動,使用 Safari 七天後,Safari 就會從快取中清除所有內容。這項移除政策不適用於已新增至主畫面的 PWA。詳情請參閱 WebKit 網誌的「完整第三方 Cookie 封鎖及其他功能」。

額外步驟:為何要針對 IndexedDB 使用包裝函式

IndexedDB 是低階 API,需要先經過大幅設定才能使用,儲存簡單資料可能會變得特別麻煩。它與大多數以承諾為基礎的新型 API 不同,其是以事件為基礎。Promise 包裝函式 (例如 IndexedDB 的 idb) 隱藏了部分強大的功能,但更重要的是隱藏 IndexedDB 程式庫隨附的複雜機器,例如交易、結構定義版本管理。

結論

儲存空間有限,使用者即將儲存更多資料。網站可以有效儲存執行所需的所有資源和資料。使用 StorageManager API 可決定您可以使用的數量以及已使用多少。此外,只要使用永久儲存空間,除非使用者移除儲存空間,否則您可以保護其不受撤銷影響。

其他資源

感謝

特別感謝 Jarryd Goodman、Phil Walton、Eiji Kitamura、Daniel Murphy、Darwin Huang、Josh Bell、Marijn Kruisselbrink 和 Victor Costan, 感謝您閱讀這篇文章。感謝 Eiji Kitamura、Addy Osmani 和 Marc Cohen 撰寫出撰寫參考文獻的原著文章。Eiji 編寫了名為瀏覽器儲存空間濫用行為的實用工具,有助於驗證目前行為。讓您盡可能儲存最多資料,並查看瀏覽器的儲存空間限制。感謝 Francois Beaufort,他在瀏覽 Safari 後,才找出儲存空間上限。

主頁橫幅是由 Guillaume Bolduc 中的 Unsplash 網站上。