O padrão de Módulo Assíncrono (AMD) é uma abordagem para carregar e gerenciar dependências de módulos em ambientes de navegador. Ao contrário da carga síncrona, ele permite que a execução continue enquanto os scripts são baixados em segundo plano. Esta técnica é fundamental para evitar o bloqueio da renderização da página. Ferramentas como o require.js implementam este conceito. Embora não faça parte dos 23 padrões de design clássicos, é considerado um padrão arquitetural amplamente adotado.
O principal objetivo do AMD é resolver os desafios do desenvolvimento front end, onde os arquivos JavaScript precisam ser carregados de forma assíncrona. Isso garante que a interface do usuário permaneça responsiva durante o carregamento dos recursos. O padrão também ajuda a resolver conflitos de nomes de variáveis e funções em projetos com múltiplas equipes, pois encapsula o código em escopos isolados. Além disso, permite que funcionalidades não essenciais para a renderização inicial sejam carregadas posteriormente, melhorando o desempenho percebido.
Abaixo, um exemplo simplificado de um carregador de módulos que suporta dependências assíncronas:
// module-dom.js
define("modulo/dom", function() {
const elemento = (identificador) => document.getElementById(identificador);
return {
buscar: elemento,
definirConteudo: (id, texto) => {
const el = elemento(id);
if (el) el.innerHTML = texto;
}
};
});
// module-eventos.js
define("modulo/eventos", ["modulo/dom"], (domModulo) => {
return {
vincular: (idElemento, tipoEvento, handler) => {
const elem = domModulo.buscar(idElemento);
if (elem) {
elem.addEventListener(tipoEvento, handler);
}
}
};
});
O código do carregador central que gerencia o cache, as dependências e o carregamento assíncrono pode ser estruturado da seguinte forma:
<script>
const SistemaDeModulos = (() => {
const cacheModulos = new Map();
const resolverCaminho = (nomeModulo) => `${nomeModulo}.js`;
const carregarScript = (url) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.async = true;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
};
const processarDefinicao = (nome, deps, fabrica) => {
const resolucoes = deps.map(dep => carregarModulo(dep));
Promise.all(resolucoes).then(modulosDependentes => {
const instanciaModulo = fabrica(...modulosDependentes);
cacheModulos.set(nome, instanciaModulo);
});
};
const carregarModulo = (nome) => {
if (cacheModulos.has(nome)) {
return Promise.resolve(cacheModulos.get(nome));
}
return new Promise((resolve) => {
carregarScript(resolverCaminho(nome)).then(() => {
const modulo = cacheModulos.get(nome);
resolve(modulo);
});
});
};
window.define = (nome, dependencias, fabrica) => {
if (!fabrica) {
fabrica = dependencias;
dependencias = [];
}
processarDefinicao(nome, dependencias, fabrica);
};
return { carregar: carregarModulo };
})();
</script>
<script>
// Uso do sistema
SistemaDeModulos.carregar("modulo/eventos").then((eventos) => {
SistemaDeModulos.carregar("modulo/dom").then((dom) => {
document.getElementById('botao').addEventListener('click', () => {
dom.definirConteudo('resultado', 'Ação executada');
});
});
});
</script>
Esta implementação deomnstra como o AMD gerencia dependências de forma assíncrona e mantém um cache de módulos já carrregados. O uso de Promises modernas substitui o callback hell, tornando o fluxo de carregamento mais linear e legível.