Conheça as práticas recomendadas para sincronizar o estado do aplicativo entre o IndexedDB e as bibliotecas de gerenciamento de estado mais conhecidas.
Quando um usuário carrega um site ou aplicativo pela primeira vez, geralmente há uma quantidade razoável de trabalho envolvida na construção do estado inicial do aplicativo usado para renderizar a interface. Por exemplo, às vezes o app precisa autenticar o usuário no lado do cliente e fazer várias solicitações de API antes de ter todos os dados necessários para exibir na página.
Armazenar o estado do aplicativo no IndexedDB pode ser uma ótima maneira de acelerar o tempo de carregamento para visitas repetidas. O app pode sincronizar com qualquer serviço de API em segundo plano e atualizar a interface com novos dados de forma lenta, empregando uma estratégia de revalidação de dados desatualizados.
No entanto, ao usar o IndexedDB, há muitas coisas importantes a considerar que podem não ser imediatamente óbvias para desenvolvedores novos nas APIs. Este documento responde a perguntas comuns e discute algumas das coisas mais importantes a serem consideradas ao persistir o estado do aplicativo no IndexedDB.
Mantenha o app previsível
Muitas das complexidades da IndexedDB vêm do fato de que há muitos fatores que você (o desenvolvedor) não controla. Esta seção aborda vários dos problemas que você precisa considerar ao trabalhar com o IndexedDB.
As gravações no armazenamento podem falhar
Erros ao gravar no IndexedDB podem acontecer por vários motivos, e, em alguns casos, esses motivos estão fora do seu controle como desenvolvedor. Por exemplo, alguns navegadores não permitem gravar no IndexedDB no modo de navegação anônima. Também há a possibilidade de um usuário estar em um dispositivo que está quase sem espaço em disco, e o navegador vai restringir o armazenamento de qualquer coisa.
Por isso, é extremamente importante implementar sempre o tratamento de erros adequado no código do IndexedDB. Isso também significa que, em geral, é uma boa ideia manter o estado do aplicativo na memória (além de armazená-lo), para que a interface não quebre quando executada no modo de navegação particular ou quando o espaço de armazenamento não estiver disponível (mesmo que alguns dos outros recursos do app que exigem armazenamento não funcionem).
Os dados armazenados podem ter sido modificados ou excluídos pelo usuário
Ao contrário dos bancos de dados do lado do servidor, em que é possível restringir o acesso não autorizado, os bancos de dados do lado do cliente são acessíveis a extensões de navegador e ferramentas para desenvolvedores e podem ser limpos pelo usuário.
Embora seja incomum os usuários modificarem os dados armazenados localmente, é muito comum eles limparem esses dados. É importante que o aplicativo possa processar esses dois casos sem erros.
Os dados armazenados podem estar desatualizados
Assim como na seção anterior, mesmo que o usuário não tenha modificado os dados, também é possível que os dados armazenados tenham sido gravados por uma versão anterior do código, possivelmente uma versão com bugs.
A IndexedDB tem suporte integrado a versões de esquema e upgrade usando o método
IDBOpenDBRequest.onupgradeneeded()
. No entanto, você ainda
precisa escrever o código de upgrade de forma que ele possa processar o usuário vindo
de uma versão anterior (incluindo uma versão com um bug).
Os testes de unidade podem ser muito úteis aqui, já que muitas vezes não é viável testar manualmente todos os casos e caminhos de upgrade possíveis.
Manter o desempenho do app
Um dos principais recursos do IndexedDB é a API assíncrona, mas não se engane e pense que não é preciso se preocupar com o desempenho ao usá-la. Há vários casos em que o uso inadequado ainda pode bloquear a linha de execução principal, o que pode levar à falta de resposta.
Como regra geral, as leituras e gravações no IndexedDB não podem ser maiores do que o necessário para os dados que estão sendo acessados.
Embora o IndexedDB permita armazenar objetos grandes e aninhados como um único registro (e isso seja bastante conveniente do ponto de vista do desenvolvedor), essa prática precisa ser evitada. Isso acontece porque, quando a IndexedDB armazena um objeto, ela precisa primeiro criar um clone estruturado desse objeto, e o processo de clonagem estruturada acontece na linha de execução principal. Quanto maior o objeto, maior será o tempo de bloqueio.
Isso apresenta alguns desafios ao planejar como persistir o estado do aplicativo no IndexedDB, já que a maioria das bibliotecas de gerenciamento de estado conhecidas (como Redux) funcionam gerenciando toda a árvore de estado como um único objeto JavaScript.
Embora o gerenciamento de estado dessa maneira tenha muitos benefícios, e armazenar a árvore de estado inteira como um único registro no IndexedDB possa ser tentador e conveniente, fazer isso após cada mudança (mesmo que com restrição/debounce) resultará em bloqueio desnecessário da linha de execução principal, aumentará a probabilidade de erros de gravação e, em alguns casos, até mesmo fará com que a guia do navegador falhe ou pare de responder.
Em vez de armazenar toda a árvore de estados em um único registro, divida-a em registros individuais e atualize apenas os registros que realmente mudam.
Como acontece com a maioria das práticas recomendadas, essa não é uma regra de tudo ou nada. Nos casos em que não é viável dividir um objeto de estado e gravar apenas o conjunto de mudanças mínimo, dividir os dados em subárvores e gravar apenas elas ainda é preferível a gravar sempre a árvore de estado inteira. Pequenas melhorias são melhores do que nenhuma melhoria.
Por fim, sempre meça o impacto no desempenho do código que você escreve. Embora seja verdade que as gravações pequenas na IndexedDB terão um desempenho melhor do que as grandes, isso só é importante se as gravações na IndexedDB que seu aplicativo está fazendo realmente levarem a tarefas longas que bloqueiam a linha de execução principal e degradam a experiência do usuário. É importante medir para entender o que você está otimizando.
Conclusões
Os desenvolvedores podem usar mecanismos de armazenamento do cliente, como o IndexedDB, para melhorar a experiência do usuário do app, não apenas mantendo o estado em todas as sessões, mas também diminuindo o tempo necessário para carregar o estado inicial em visitas repetidas.
Embora o uso adequado da IndexedDB possa melhorar drasticamente a experiência do usuário, o uso incorreto ou a falha na manipulação de casos de erro pode levar a apps corrompidos e usuários insatisfeitos.
Como o armazenamento do cliente envolve muitos fatores fora do seu controle, é essencial que seu código seja bem testado e processe corretamente os erros, mesmo aqueles que podem parecer improváveis de ocorrer.