W3docs

JavaScript IndexedDB

Aprenda JavaScript IndexedDB: abra um banco de dados, trate onupgradeneeded, crie object stores e índices, execute transações, e adicione, obtenha, atualize e exclua registros com cursores.

IndexedDB é uma API de armazenamento client-side poderosa, mais robusta do que outras soluções de armazenamento local disponíveis nos navegadores web. Ela permite que aplicações web armazenem e manipulem quantidades significativas de dados estruturados de forma assíncrona. O IndexedDB é ideal para aplicações que exigem armazenamento de dados offline, alto desempenho e capacidades de consulta avançadas sem dependência de uma conexão de rede.

Este capítulo abrange tudo o que você precisa para começar a usar o IndexedDB: abrir um banco de dados e tratar atualizações de versão, criar object stores e índices, executar transações e realizar o ciclo CRUD completo (adicionar, obter, atualizar, excluir), incluindo iteração com cursores e consultas por meio de índices.

Quando usar o IndexedDB

O IndexedDB armazena praticamente qualquer valor JavaScript — objetos, arrays, datas, blobs e arquivos — não apenas strings, e pode armazenar centenas de megabytes, muito além do limite de ~5 MB do localStorage e sessionStorage. É um armazenamento NoSQL de chave/valor transacional com índices, o que o torna a escolha certa para:

  • Aplicações offline-first que precisam funcionar sem uma conexão de rede.
  • Cache de grandes conjuntos de dados, como respostas de API, documentos ou arquivos de mídia.
  • Consultas de registros por campos indexados, em vez de carregar tudo na memória.

Se você só precisa persistir alguns valores de string pequenos, prefira as APIs de Web Storage mais simples. Consulte o capítulo Storage API para uma visão geral de como o navegador gerencia cotas de armazenamento entre esses mecanismos.

A API assíncrona baseada em eventos

Cada operação do IndexedDB é assíncrona e orientada a eventos. Chamadas como indexedDB.open() ou store.get() retornam imediatamente um objeto de request; o resultado real chega posteriormente por meio dos handlers de eventos onsuccess / onerror. Seu código nunca bloqueia aguardando E/S de disco. Por causa disso, você não pode ler um resultado de forma síncrona logo após emitir uma solicitação — você deve aguardar o disparo do evento. (O código moderno frequentemente encapsula essas solicitações em Promises, mas a API nativa em si é baseada em callbacks, que é o que os exemplos abaixo utilizam.)

Configurando um Banco de Dados IndexedDB

Passo 1: Abrir um Banco de Dados

Para usar o IndexedDB, o primeiro passo é abrir um banco de dados com indexedDB.open(name, version). O segundo argumento opcional é um número de versão inteiro. Se o banco de dados não existir, ou se a versão solicitada for maior do que a armazenada, o evento onupgradeneeded é disparado — este é o único lugar onde você pode alterar a estrutura do banco de dados (criar ou excluir object stores e índices).

A chamada retorna uma solicitação e pode disparar três eventos:

  • onsuccess — o banco de dados foi aberto e está pronto para uso (event.target.result é o IDBDatabase).
  • onerror — a abertura falhou.
  • onupgradeneeded — uma mudança de esquema é necessária (consulte o Passo 2).

Veja como você pode criar ou abrir um banco de dados IndexedDB. Após uma operação bem-sucedida, fechamos o banco de dados para evitar efeitos colaterais indesejados em outros exemplos. Você pode omitir este passo no seu próprio código, ou incluí-lo se necessário.

Aviso: Chamar deleteDatabase() apagará todos os dados desse banco de dados. Isso é apenas para fins de teste e não deve ser usado em produção.


javascript— editable

Passo 2: Criando Object Stores

Depois que o banco de dados é aberto, você pode criar uma object store, que é análoga a uma tabela em bancos de dados relacionais. Observe que isso só pode ser feito durante uma atualização de versão (ao abrir o banco de dados com um número de versão maior). O evento a ser observado é onupgradeneeded.

Ao criar uma store, você escolhe como a chave primária de cada registro é definida:

  • { keyPath: 'id' } — a chave é lida a partir da propriedade id de cada objeto armazenado (uma chave inline).
  • { keyPath: 'id', autoIncrement: true } — a store gera uma chave sequencial automaticamente se você não fornecer uma.
  • { autoIncrement: true } — as chaves são geradas e armazenadas separadamente do valor (uma chave out-of-line).

Você também cria índices dentro de onupgradeneeded. Um índice permite buscar registros por uma propriedade diferente da chave primária. Passe { unique: true } para rejeitar valores duplicados para aquela propriedade.


javascript— editable

Transações

Depois que seu banco de dados e object stores estão configurados, você precisará gerenciar as operações de dados usando transações. Uma transação no IndexedDB é um mecanismo que agrupa múltiplas operações em uma única unidade de trabalho que ou é concluída com sucesso na íntegra, ou falha completamente. É essencial para garantir a consistência e integridade dos dados, especialmente quando múltiplas operações dependem umas das outras para produzir um resultado correto.

Como Usar Transações no IndexedDB

Passo 1: Iniciando uma Transação

Para realizar qualquer operação no IndexedDB, você começa criando uma transação em um banco de dados. Uma transação é criada especificando quais object stores a transação vai envolver e o modo da transação, que pode ser "readonly" ou "readwrite".

Passo 2: Acessando uma Object Store

Dentro de uma transação, você pode acessar uma ou mais object stores para realizar operações de dados.

Passo 3: Realizando Operações

Assim que você tem acesso a uma object store, pode executar várias operações, como adicionar, recuperar, atualizar ou excluir dados. Cada operação retorna um objeto de solicitação que você pode usar para tratar eventos de sucesso ou erro.

Passo 4: Concluindo a Transação

Uma transação será concluída automaticamente assim que todas as operações emitidas nela forem resolvidas, seja por sucesso ou por falha. Você também pode ouvir o evento complete na transação para executar ações depois que todas as operações forem concluídas com sucesso.

Aqui está um exemplo de uma transação completa:


javascript— editable

Lendo Dados

Para recuperar dados, use store.get(key) ou um cursor para iterar sobre múltiplos registros. Aqui estão exemplos rápidos:

Recuperando um único registro:


javascript— editable

Iterando com um cursor:


javascript— editable

Consultando com Índices

A chave primária permite buscar um registro quando você já conhece sua chave. Um índice permite pesquisar por outra propriedade — por exemplo, encontrar um livro pelo seu title. Acesse um índice com store.index(name), depois chame get(), getAll() ou openCursor() nele, assim como faria em uma store.

Buscando um registro por uma propriedade indexada:


javascript— editable

Você também pode restringir uma consulta a um intervalo de chaves com IDBKeyRange (por exemplo, IDBKeyRange.bound('A', 'M') para buscar todos os livros cujo título começa entre A e M), passando o intervalo para getAll() ou openCursor().

Atualizando e Excluindo Registros

Para modificar dados existentes, use store.put() com a mesma chave. Para remover dados, use store.delete(key).

Atualizando um registro:


javascript— editable

Excluindo um registro:


javascript— editable

Como visualizar o conteúdo do IndexedDB no seu navegador

Após armazenar e manipular dados, você pode querer inspecionar o que está realmente salvo no seu navegador. A maioria dos navegadores modernos exibe o que está armazenado no IndexedDB. Abaixo está o exemplo das ferramentas de desenvolvedor do Chrome:

IndexedDB

Boas Práticas para Usar Transações

Para garantir que sua implementação de IndexedDB permaneça confiável e com bom desempenho, siga estas diretrizes:

  1. Minimize o Escopo: Mantenha as transações o menores possível, tanto em termos de número de operações quanto de duração. Isso reduz a probabilidade de conflitos e melhora o desempenho.
  2. Tratamento de Erros: Sempre implemente tratamento de erros tanto no nível da solicitação quanto da transação. Isso ajuda a diagnosticar problemas e evitar atualizações parciais que poderiam levar à corrupção de dados.
  3. Concorrência: Entenda que, embora o IndexedDB seja assíncrono e não bloqueante, as transações no mesmo banco de dados são enfileiradas e executadas em série para evitar condições de corrida e inconsistências.

Conclusão

O IndexedDB fornece uma plataforma robusta para o gerenciamento complexo de dados em aplicações web, tornando-o uma ferramenta essencial para desenvolvedores web modernos. Por meio da implementação adequada de seus recursos, os desenvolvedores podem armazenar, recuperar, atualizar e excluir dados client-side de forma eficiente, melhorando o desempenho da aplicação e a experiência do usuário.

Para necessidades de armazenamento mais simples e para entender o panorama mais amplo de armazenamento no navegador, consulte estes capítulos relacionados:

  • localStorage e sessionStorage — armazenamento leve de chave/valor para pequenas quantidades de dados em string.
  • A Storage API — como o navegador gerencia cotas de armazenamento e persistência entre os mecanismos.
  • Trabalhando com JSON — serialização de dados, útil ao mover objetos para dentro e fora do armazenamento.

Prática

Prática
Quais são as características do IndexedDB em JavaScript?
Quais são as características do IndexedDB em JavaScript?
Was this page helpful?