Browser-Speicher im Vergleich: localStorage, IndexedDB, Cache API und OPFS

技术架构

Übersicht über fünf Browser-Speichermechanismen

Moderne Browser bieten 5 primäre Speichermechanismen, die jeweils für unterschiedliche Ziele und Anwendungsfälle konzipiert sind:

Speicher Datentyp Kapazitätsgrenze Persistenz Thread-Zugriff
localStorage String-Schlüssel-Wert ~5-10 MB Dauerhaft Nur Haupt-Thread
sessionStorage String-Schlüssel-Wert ~5-10 MB Tab-Schließung Nur Haupt-Thread
IndexedDB Strukturierte Daten + Blob Hunderte MB~unbegrenzt Dauerhaft Haupt-Thread + Worker
Cache API Request/Response-Paare Geteilt mit IndexedDB-Kontingent Dauerhaft Haupt-Thread + Worker
OPFS Dateisystem Geteilt mit IndexedDB-Kontingent Dauerhaft Nur Worker (synchron)

localStorage und sessionStorage

Grundlegende Verwendung

localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
localStorage.removeItem('theme');
localStorage.clear();

for (let i = 0; i < localStorage.length; i++) {
  const key = localStorage.key(i);
  console.log(key, localStorage.getItem(key));
}

Wesentliche Unterschiede

Merkmal localStorage sessionStorage
Lebensdauer Dauerhaft Beim Tab-Schließen gelöscht
Gültigkeitsbereich Geteilt zwischen Tabs gleicher Herkunft Nur aktueller Tab
Typische Verwendung Benutzereinstellungen, Tokens Formularentwürfe, Seitenzustand

Kapazitätserkennung

function testLocalStorageQuota() {
  const testKey = '__quota_test__';
  let data = '';
  try {
    for (let i = 0; i < 1024; i++) data += 'a'.repeat(1024);
    for (let mb = 1; mb < 20; mb++) {
      localStorage.setItem(testKey, data.repeat(mb));
    }
  } catch (e) {
    console.log('localStorage quota exceeded');
  } finally {
    localStorage.removeItem(testKey);
  }
}

Hinweise

  • Synchrones Blockieren: Lesen/Schreiben blockiert den Haupt-Thread; große Daten beeinträchtigen die Leistung
  • Nur Strings: Objekte benötigen JSON.stringify/JSON.parse
  • Storage-Ereignis: Löst das storage-Ereignis in anderen Tabs gleicher Herkunft bei Änderung aus

IndexedDB

Grundlegende Verwendung

const openRequest = indexedDB.open('myDatabase', 1);

openRequest.onupgradeneeded = (event) => {
  const db = event.target.result;
  const store = db.createObjectStore('users', { keyPath: 'id' });
  store.createIndex('name', 'name', { unique: false });
};

openRequest.onsuccess = (event) => {
  const db = event.target.result;
  const tx = db.transaction('users', 'readwrite');
  const store = tx.objectStore('users');

  store.add({ id: 1, name: 'Alice', email: 'alice@example.com' });

  store.get(1).onsuccess = (e) => {
    console.log(e.target.result);
  };
};

Erweiterte Funktionen

Funktion Beschreibung
Transaktionen Garantiert Atomarität, Lese-/Schreibtrennung
Indizes Effiziente Abfragen auf Nicht-Schlüsselfeldern
Cursor Große Datensätze iterieren ohne alles gleichzeitig zu laden
Blob-Speicherung File- und Blob-Objekte direkt speichern
Worker-Zugriff Verfügbar in Service Workers und Web Workers

Vereinfacht mit der idb-Bibliothek

import { openDB } from 'idb';

const db = await openDB('myDatabase', 1, {
  upgrade(db) {
    db.createObjectStore('users', { keyPath: 'id' });
  }
});

await db.put('users', { id: 1, name: 'Alice' });
const user = await db.get('users', 1);
const allUsers = await db.getAll('users');
await db.delete('users', 1);

Cache API

Grundlegende Verwendung

const cache = await caches.open('v1');

await cache.put('/api/data', new Response(JSON.stringify({ foo: 'bar' })));

const response = await cache.match('/api/data');
const data = await response.json();

await cache.delete('/api/data');

Mit Service Worker

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cached) => {
      if (cached) return cached;
      return fetch(event.request).then((response) => {
        const clone = response.clone();
        caches.open('v1').then((cache) => {
          cache.put(event.request, clone);
        });
        return response;
      });
    })
  );
});

Vergleich von Caching-Strategien

Strategie Beschreibung Anwendungsfall
Cache First Zuerst Cache, Netzwerk bei Fehlen Statische Assets, Schriftarten
Network First Zuerst Netzwerk, Cache als Fallback API-Daten, häufig aktualisierter Inhalt
Stale While Revalidate Cache zurückgeben, im Hintergrund aktualisieren Nicht-kritische APIs, Bilder
Cache Only Nur Cache Offline-Seiten, vorgecachte Ressourcen
Network Only Nur Netzwerk Non-GET-Anfragen, Echtzeitdaten

OPFS (Origin Private File System)

Grundlegende Verwendung

const root = await navigator.storage.getDirectory();

const fileHandle = await root.getFileHandle('data.bin', { create: true });
const writable = await fileHandle.createWritable();
await writable.write(new Uint8Array([1, 2, 3, 4]));
await writable.close();

const file = await fileHandle.getFile();
const buffer = await file.arrayBuffer();

Synchroner Zugriff in Workern

// In einem Worker — synchrones OPFS (extrem schnell)
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('large.bin', { create: true });
const accessHandle = await fileHandle.createSyncAccessHandle();

const buffer = new ArrayBuffer(4);
accessHandle.write(buffer, { at: 0 });
accessHandle.flush();
accessHandle.close();

OPFS vs File System Access API

Merkmal OPFS File System Access API
Benutzerberechtigung Nicht erforderlich Benutzer muss Verzeichnis auswählen
Sichtbarkeit Browser-internes virtuelles Dateisystem Echtes Betriebssystem-Dateisystem
Worker-Sync Unterstützt Nicht unterstützt
Persistenz Dauerhaft Hängt von Benutzerberechtigung ab
Anwendungsfall Hochleistungs-Temporärdateiverarbeitung Dateieditoren, Export

Speicherkontingent und Persistenz

Verfügbares Kontingent abfragen

const estimate = await navigator.storage.estimate();
console.log(`Used: ${(estimate.usage / 1024 / 1024).toFixed(2)} MB`);
console.log(`Quota: ${(estimate.quota / 1024 / 1024).toFixed(2)} MB`);

Persistenz anfordern

const persisted = await navigator.storage.persist();
if (persisted) {
  console.log('Storage persisted, will not be auto-evicted');
} else {
  console.log('Storage may be cleared under pressure');
}

Browser können nicht-persistenten Speicher unter Druck automatisch entfernen. Rufen Sie navigator.storage.persist() auf, um Persistenz anzufordern.


Entscheidungsleitfaden

What do you need to store?
├── Simple key-value (< 5MB)
│   ├── Cross-tab sharing → localStorage
│   └── Current tab only → sessionStorage
├── Structured data / many records
│   └── IndexedDB
├── HTTP request/response caching
│   └── Cache API
└── Large files / binary / high-performance I/O
    └── OPFS

Praxisbeispiele

Szenario Empfohlener Speicher Grund
BenutzertHEMA-Einstellung localStorage Einfaches Schlüssel-Wert, seitenübergreifend
Formularentwurf sessionStorage Temporär, tab-bezogen
Offline-Tool-Daten IndexedDB Strukturiert, indizierte Abfragen
Statische Asset-Cache Cache API Für Request/Response konzipiert
Videoverarbeitungs-Temporärdateien OPFS Synchrone Worker-E/A, hohe Leistung

Sicherheitsaspekte

  • XSS-Risiko: localStorage ist durch XSS lesbar — niemals sensible Tokens speichern
  • HttpOnly-Cookies: Auth-Tokens sollten HttpOnly + Secure-Cookies verwenden
  • Speicherverschlüsselung: Sensible Daten vor dem Speichern mit JWT oder Hash verschlüsseln
  • Same-Origin-Isolierung: Alle Speicher folgen der Same-Origin-Richtlinie; Cross-Origin-Zugriff ist blockiert

Zusammenfassung

Der Browser-Speicher hat sich von einem einzelnen localStorage zu einem vollständigen System entwickelt, das Schlüssel-Wert-Paare, strukturierte Daten, HTTP-Caching und Dateisysteme abdeckt. Der Schlüssel zur Auswahl ist die Übereinstimmung mit den Datenmerkmalen: einfache Konfiguration → localStorage, strukturierte Daten → IndexedDB, HTTP-Caching → Cache API, hochperformante Datei-E/A → OPFS.

Verwenden Sie den Cookie-Parser zur Überprüfung der Cookie-Konfiguration, das JWT-Tool zur Überprüfung der Token-Sicherheit und das Hash-Tool zum Hashen sensibler Daten.

Probiere diese browser-lokalen Tools aus — keine Registrierung erforderlich →

#localStorage#sessionStorage#IndexedDB#Cache API#存储对比