IndexedDB 實戰:瀏覽器端大檔案儲存與離線架構

技术架构(更新於 2026年5月22日)

為什麼需要 IndexedDB?

瀏覽器儲存方案各有侷限:

方案 容量 資料類型 同步 API 適用場景
Cookie ~4KB 字串 工作階段識別
localStorage ~5MB 字串 簡單設定
sessionStorage ~5MB 字串 暫時狀態
IndexedDB 數百 MB~GB 任意結構化資料 ❌ 非同步 大檔案、離線應用

對於需要在瀏覽器中快取 PDF 處理中間結果、WASM 模組,或使用者上傳歷史紀錄的工具站,IndexedDB 是唯一可行的選擇。


核心概念

資料庫 → 物件儲存 → 紀錄

Database: "toolsku-cache"
  ├── ObjectStore: "wasm-modules"     (key: moduleName)
  ├── ObjectStore: "file-cache"       (key: fileHash, index: timestamp)
  └── ObjectStore: "user-preferences" (key: settingKey)

交易與並行

IndexedDB 的交易是自動提交的,且同一時刻每個 ObjectStore 只能有一個讀寫交易:

const tx = db.transaction(['file-cache'], 'readwrite');
const store = tx.objectStore('file-cache');
await store.put({ hash: 'abc123', data: arrayBuffer, timestamp: Date.now() });
await tx.done; // 等待交易完成

工具庫中的 IndexedDB 應用

WASM 模組快取

ffmpeg.wasm 約 30MB,每次載入耗時 3–5 秒。快取到 IndexedDB 後,二次存取幾乎零延遲:

async function getWasmModule(name: string): Promise<ArrayBuffer> {
  const cached = await idb.get('wasm-modules', name);
  if (cached) return cached;

  const response = await fetch(`/wasm/${name}.wasm`);
  const buffer = await response.arrayBuffer();
  await idb.put('wasm-modules', buffer, name);
  return buffer;
}

大檔案分塊儲存

超過 50MB 的檔案不適合一次性存入 IndexedDB。分塊策略:

檔案 (200MB) → 切分為 4MB chunks → 分別存入 IndexedDB
key: "file:{hash}:chunk:{index}"
讀取時按序拼接 → 還原完整檔案

版本遷移

資料庫 schema 變更時需要 onupgradeneeded 處理遷移:

const request = indexedDB.open('toolsku-cache', 2); // 版本號 2

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  if (event.oldVersion < 2) {
    db.createObjectStore('processing-history', { keyPath: 'id' });
  }
};

最佳實務:只增不減 ObjectStore,透過版本號遞增觸發遷移,避免刪除使用者資料。


IndexedDB vs OPFS

特性 IndexedDB OPFS (Origin Private File System)
API 成熟度 廣泛支援 Chrome 86+ / Safari 15.2+
讀寫模式 鍵值儲存 真正的檔案系統
效能 中等 更高(尤其同步存取)
適用 結構化快取 大檔案讀寫

工具庫目前以 IndexedDB 為主,OPFS 作為 Chrome 上的效能優化備選。


總結

IndexedDB 是建構離線優先瀏覽器工具的關鍵基礎設施。合理設計 ObjectStore、利用 WASM 快取、實施分塊儲存策略,可以讓工具庫在弱網環境下仍提供流暢體驗。

本站提供瀏覽器本地工具,免註冊即可試用 →

#IndexedDB#浏览器存储#离线#大文件#架构