Comparação de armazenamento do navegador: localStorage, IndexedDB, Cache API e OPFS

技术架构

Visão geral dos cinco mecanismos de armazenamento do navegador

Os navegadores modernos oferecem 5 mecanismos de armazenamento principais, cada um projetado para diferentes objetivos e casos de uso:

Armazenamento Tipo de dados Limite de capacidade Persistência Acesso por thread
localStorage Chave-valor de string ~5-10 MB Permanente Apenas thread principal
sessionStorage Chave-valor de string ~5-10 MB Ao fechar aba Apenas thread principal
IndexedDB Dados estruturados + Blob Centenas de MB~ilimitado Permanente Thread principal + Worker
Cache API Pares Request/Response Compartilhado com cota do IndexedDB Permanente Thread principal + Worker
OPFS Sistema de arquivos Compartilhado com cota do IndexedDB Permanente Apenas Worker (síncrono)

localStorage e sessionStorage

Uso básico

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));
}

Diferenças principais

Característica localStorage sessionStorage
Duração Permanente Limpo ao fechar aba
Escopo Compartilhado entre abas de mesma origem Apenas aba atual
Uso típico Preferências do usuário, tokens Rascunhos de formulário, estado da página

Detecção de capacidade

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);
  }
}

Ressalvas

  • Bloqueio síncrono: Leitura/escrita bloqueia a thread principal; dados grandes prejudicam o desempenho
  • Apenas strings: Objetos precisam de JSON.stringify/JSON.parse
  • Evento storage: Dispara o evento storage em outras abas de mesma origem ao ser modificado

IndexedDB

Uso básico

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);
  };
};

Recursos avançados

Recurso Descrição
Transações Garante atomicidade, separação leitura/escrita
Índices Consultas eficientes em campos não-chave
Cursores Iterar grandes conjuntos de dados sem carregar tudo de uma vez
Armazenamento Blob Armazenar objetos File e Blob diretamente
Acesso por Worker Disponível em Service Workers e Web Workers

Simplificado com a biblioteca idb

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

Uso básico

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');

Com 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;
      });
    })
  );
});

Comparação de estratégias de cache

Estratégia Descrição Caso de uso
Cache First Cache primeiro, rede se não encontrado Recursos estáticos, fontes
Network First Rede primeiro, cache como fallback Dados de API, conteúdo atualizado frequentemente
Stale While Revalidate Retornar cache, atualizar em segundo plano APIs não críticas, imagens
Cache Only Apenas cache Páginas offline, recursos pré-cacheados
Network Only Apenas rede Requisições não GET, dados em tempo real

OPFS (Origin Private File System)

Uso básico

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();

Acesso síncrono em Workers

// Em um Worker — OPFS síncrono (extremamente rápido)
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

Característica OPFS File System Access API
Permissão do usuário Não necessária Usuário deve selecionar diretório
Visibilidade Sistema de arquivos virtual interno do navegador Sistema de arquivos real do SO
Sync em Worker Suportado Não suportado
Persistência Permanente Depende de concessão do usuário
Caso de uso Processamento de arquivos temporários de alto desempenho Editores de arquivos, exportação

Cota de armazenamento e persistência

Consultar cota disponível

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`);

Solicitar persistência

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');
}

Navegadores podem remover automaticamente o armazenamento não persistente sob pressão. Chame navigator.storage.persist() para solicitar persistência.


Guia de decisão

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

Exemplos do mundo real

Cenário Armazenamento recomendado Razão
Preferência de tema do usuário localStorage Chave-valor simples, entre páginas
Rascunho de formulário sessionStorage Temporário, escopo da aba
Dados de ferramenta offline IndexedDB Estruturado, consultas indexadas
Cache de recursos estáticos Cache API Projetado para Request/Response
Arquivos temporários de processamento de vídeo OPFS E/S síncrona em Worker, alto desempenho

Considerações de segurança

  • Risco XSS: localStorage é legível por XSS — nunca armazene tokens sensíveis
  • Cookies HttpOnly: Tokens de autenticação devem usar cookies HttpOnly + Secure
  • Criptografia de armazenamento: Criptografe dados sensíveis com JWT ou Hash antes de armazenar
  • Isolamento de mesma origem: Todo armazenamento segue a política de mesma origem; acesso entre origens é bloqueado

Resumo

O armazenamento do navegador evoluiu de um único localStorage para um sistema completo que abrange pares chave-valor, dados estruturados, cache HTTP e sistemas de arquivos. A chave para a seleção é corresponder às características dos dados: configuração simples → localStorage, dados estruturados → IndexedDB, cache HTTP → Cache API, E/S de arquivos de alto desempenho → OPFS.

Use o Analisador de Cookies para inspecionar a configuração de cookies, a Ferramenta JWT para verificar a segurança de tokens, e a Ferramenta Hash para hashear dados sensíveis.

Experimente estas ferramentas executadas localmente no navegador — nenhum cadastro necessário →

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