Na última década,
fornecedores de navegadores e especialistas em desempenho da Web têm dito que o localStorage
é lento,
e os desenvolvedores da Web precisam parar de usá-lo.
Para ser justo, as pessoas que dizem isso não estão erradas. A localStorage
é uma
API síncrona que bloqueia a linha de execução principal. Sempre que você a acessa, pode impedir que sua página seja interativa.
O problema é que a API localStorage
é muito simples, e a única
alternativa assíncrona ao localStorage
é o
IndexedDB,
que não é conhecida por sua facilidade de uso ou por ser uma API acolhedora.
Assim, os desenvolvedores podem escolher entre algo difícil de usar e algo
ruim para o desempenho. Embora existam bibliotecas que oferecem a simplicidade
da API localStorage
enquanto efetivamente usam APIs de armazenamento assíncrono
em segundo plano, incluir uma dessas bibliotecas no app tem um custo de tamanho de arquivo e
pode consumir seu orçamento de desempenho.
Mas e se fosse possível conseguir o desempenho de uma API de armazenamento assíncrona com a simplicidade da API localStorage
, sem precisar pagar o custo do tamanho do arquivo?
Bem, em breve pode haver. O Chrome está testando um novo recurso conhecido como módulos integrados, e o primeiro que planejamos enviar é um módulo de armazenamento de chave-valor assíncrono chamado KV Storage.
Mas antes de entrar em detalhes sobre o módulo de armazenamento do KV, vou explicar o que quero dizer com módulos integrados.
O que são módulos integrados?
Os módulos integrados são semelhantes aos módulos JavaScript normais, exceto pelo fato de não precisarem ser transferidos por download porque vêm com o navegador.
Como as APIs da Web tradicionais, os módulos integrados precisam passar por um processo de padronização. Cada um tem a própria especificação que requer uma revisão do design e sinais positivos de suporte de desenvolvedores da Web e outros fornecedores de navegadores antes de serem enviados. No Chrome, os módulos integrados seguem o mesmo processo de inicialização que usamos para implementar e enviar todas as novas APIs.
Ao contrário das APIs da Web tradicionais, os módulos integrados não são expostos no escopo global. Eles estão disponíveis apenas por importações.
Não expor módulos integrados globalmente tem muitas vantagens: elas não adicionam nenhuma sobrecarga para iniciar um novo contexto de ambiente de execução do JavaScript (por exemplo, uma nova guia, worker ou service worker) e não consomem nenhuma memória ou CPU, a menos que sejam realmente importados. Além disso, elas não correm o risco de nomear colisões com outras variáveis definidas no código.
Para importar um módulo integrado, use o prefixo std:
seguido pelo identificador
do módulo integrado. Por exemplo, em navegadores
compatíveis, é possível importar o módulo KV Storage com o código a seguir.
Confira abaixo como usar um polyfill de KV Storage em navegadores incompatíveis:
import storage, {StorageArea} from 'std:kv-storage';
O módulo KV Storage
O módulo de armazenamento KV é semelhante em sua simplicidade à API localStorage
, mas
o formato da API é mais próximo de um
Map
em JavaScript.
Em vez de getItem()
,
setItem()
e removeItem()
,
há get()
,
set()
e delete()
.
Ele também tem outros métodos semelhantes a mapas não disponíveis para localStorage
, como
keys()
,
values()
e
entries()
.
Além disso, como Map
, as chaves não precisam ser strings. Eles podem ser qualquer
tipo de serialização estruturada.
Ao contrário de Map
, todos os métodos de armazenamento do KV retornam promessas ou iteradores assíncronos, já que o ponto principal desse módulo é que ele não é síncrono, diferentemente de localStorage
. Para acessar a API completa em detalhes, consulte a especificação.
Como você deve ter notado no exemplo de código acima, o módulo KV Storage tem
uma exportação padrão storage
e uma chamada exportação StorageArea
.
storage
é uma instância da classe StorageArea
com o nome 'default'
,
e é o que os desenvolvedores vão usar com mais frequência no código do aplicativo. A
classe StorageArea
é fornecida para casos em que é necessário isolamento extra,
por exemplo, uma biblioteca de terceiros que armazena dados e quer evitar conflitos com
dados armazenados pela instância storage
padrão. Os dados de StorageArea
são armazenados em um banco de dados IndexedDB com o nome kv-storage:${name}
, em que nome é o nome da instância StorageArea
.
Confira um exemplo de como usar o módulo KV Storage no seu código:
import storage from 'std:kv-storage';
const main = async () => {
const oldPreferences = await storage.get('preferences');
document.querySelector('form').addEventListener('submit', async () => {
const newPreferences = Object.assign({}, oldPreferences, {
// Updated preferences go here...
});
await storage.set('preferences', newPreferences);
});
};
main();
E se um navegador não for compatível com um módulo integrado?
Se você está familiarizado com o uso de módulos JavaScript nativos em navegadores, provavelmente sabe que (pelo menos até agora) a importação de qualquer coisa diferente de um URL
vai gerar um erro. E std:kv-storage
não é um URL válido.
Isso levanta a questão: precisamos esperar até que todos os navegadores sejam compatíveis com módulos integrados antes de usá-los no nosso código? Felizmente, a resposta é não.
Você poderá usar os módulos integrados assim que um navegador oferecer suporte a eles, graças ao outro recurso que estamos testando, chamado de importar mapas.
Importar mapas
Os mapas de importação são essencialmente um mecanismo pelo qual os desenvolvedores podem atribuir alias aos identificadores de importação um ou mais identificadores alternativos.
Isso é eficiente porque oferece uma maneira de mudar (no tempo de execução) como um navegador resolve um identificador de importação específico em todo o aplicativo.
No caso de módulos integrados, isso permite fazer referência a um polyfill do módulo no código do aplicativo, mas um navegador que oferece suporte ao módulo integrado pode carregar essa versão.
Confira como declarar um mapa de importação para que esse recurso funcione com o módulo de armazenamento do KV:
<!-- The import map is inlined into your page -->
<script type="importmap">
{
"imports": {
"/path/to/kv-storage-polyfill.mjs": [
"std:kv-storage",
"/path/to/kv-storage-polyfill.mjs"
]
}
}
</script>
<!-- Then any module scripts with import statements use the above map -->
<script type="module">
import storage from '/path/to/kv-storage-polyfill.mjs';
// Use `storage` ...
</script>
O ponto principal no código acima é que o URL /path/to/kv-storage-polyfill.mjs
está sendo mapeado para dois recursos diferentes: std:kv-storage
e, em seguida, para o
URL original novamente, /path/to/kv-storage-polyfill.mjs
.
Assim, quando o navegador encontra uma instrução de importação referenciando esse URL
(/path/to/kv-storage-polyfill.mjs
), ele primeiro tenta carregar std:kv-storage
e, se não conseguir, volta a carregar
/path/to/kv-storage-polyfill.mjs
.
Novamente, a mágica aqui é que o navegador não precisa oferecer suporte a mapas de importação ou módulos integrados para que essa técnica funcione, já que o URL transmitido para a instrução de importação é o URL do polyfill. Na verdade, o polyfill não é um substituto, é o padrão. O módulo integrado é um aprimoramento progressivo.
E quanto aos navegadores que não são compatíveis com módulos?
Para usar mapas de importação para carregar condicionalmente módulos integrados, é necessário
usar instruções import
, o que também significa que você precisa usar scripts de módulo, ou seja,
<script type="module">
.
Atualmente, mais de 80% dos navegadores são compatíveis com módulos. Para navegadores que não são,
use a técnica de módulo/nomódulo
para disponibilizar um pacote legado. Observe que, ao gerar o build
nomodule
, você vai precisar incluir todos os polyfills, porque você sabe com certeza
que os navegadores que não oferecem suporte a módulos não vão oferecer suporte a módulos
integrados.
Demonstração do KV Storage
Para ilustrar que é possível usar módulos integrados e, ao mesmo tempo, oferecer suporte a navegadores mais antigos, montei uma demonstração que incorpora todas as técnicas descritas acima e é executada em todos os navegadores atualmente:
- Navegadores que oferecem suporte a módulos, mapas de importação e o módulo integrado não carregam códigos desnecessários.
- Os navegadores que aceitam módulos e mapas de importação, mas não aceitam o módulo integrado, carregam o polyfill de armazenamento KV (em inglês) por meio do carregador de módulos do navegador.
- Os navegadores que aceitam módulos, mas não mapas de importação, também carregam o polyfill de armazenamento KV (por meio do carregador de módulos do navegador).
- Os navegadores que não são compatíveis com módulos recebem o polyfill de armazenamento KV no
pacote legado (carregado via
<script nomodule>
).
A demonstração é hospedada no Glitch para que você possa acessar a fonte. Também temos uma explicação detalhada sobre a implementação no README (em inglês). Sinta-se à vontade para conferir se tiver curiosidade de ver como ele é construído.
Para conferir o módulo integrado nativo em ação, carregue
a demonstração no Chrome 74 ou mais recente com a flag de recursos experimentais
da plataforma da Web ativada
(chrome://flags/#enable-experimental-web-platform-features
).
Você pode verificar se o módulo integrado está sendo carregado porque não verá o script de polyfill no painel de origem do DevTools. Em vez disso, verá a versão do módulo integrado (fato curioso: você pode inspecionar o código-fonte do módulo ou até mesmo colocar pontos de interrupção nele):
Envie seu feedback
Nesta introdução, você aprendeu o que é possível fazer com os módulos integrados. Esperamos que você esteja animado! Adoraríamos que os desenvolvedores testassem o módulo de armazenamento KV, assim como todos os novos recursos discutidos aqui, e nos dessem feedback.
Confira os links do GitHub em que você pode enviar feedback sobre cada um dos recursos mencionados neste artigo:
- KV Storage (link em inglês)
- Polyfill de armazenamento KV (em inglês)
- Módulos integrados.
- Importar o Maps
Se o site usa localStorage
atualmente, tente alternar para a API KV Storage para ver se ela atende a todas as suas necessidades. Se você se inscrever para o teste de origem do armazenamento KV, poderá implantar esses recursos hoje mesmo. Todos os usuários vão se beneficiar de um melhor desempenho
de armazenamento, e os usuários do Chrome 74 ou versões mais recentes não precisarão pagar nenhum custo
de download extra.