
Entretanto, essa simplicidade pode ser ilusória. Por parecer síncrono, muitos desenvolvedores iniciantes aplicam padrões incorretos que causam gargalos de performance, falhas silenciosas de tratamento de erros e comportamentos inesperados.
Abaixo, listamos os 5 erros mais comuns e como corrigi-los no seu dia a dia.
1. Criar um "Gargalo Sequencial" ao Invocá-lo sem Necessidade
Este é o erro clássico de performance. O await pausa a execução do bloco até que a Promise seja resolvida. Se você tem duas operações assíncronas independentes, usá-los sequencialmente dobra o tempo de resposta da sua aplicação.
Erro:
1async function carregarDadosDoDashboard() {
2 // A requisição de produtos só começa DEPOIS que a de usuários terminar
3 const usuarios = await fetchUsuarios();
4 const produtos = await fetchProdutos();
5
6 return { usuarios, produtos };
7}A solução:
Para requisições independentes, execute-as em paralelo utilizando Promise.all:
1async function carregarDadosDoDashboard() {
2 // Dispara ambas as requisições simultaneamente
3 const [usuarios, produtos] = await Promise.all([
4 fetchUsuarios(),
5 fetchProdutos()
6 ]);
7
8 return { usuarios, produtos };
9}2. Tentar Usar await Dentro de um Metódo Array (forEach, map)
O método .forEach() de um Array não é ciente de Promises. Passar uma função async para o .forEach() apenas dispara chamadas assíncronas em segundo plano, sem esperar o término de cada iteração.
O erro:
1async function processarUsuarios(listaIds) {
2 listaIds.forEach(async (id) => {
3 // O await aqui NÃO segura a execução do loop principal
4 const usuario = await fetchUsuarioPorId(id);
5 console.log(usuario.nome);
6 });
7
8 // Isto é executado ANTES do término do processamento das requisições!
9 console.log("Processamento concluído!");
10}A solução:
- Para processamento em paralelo: Utilize
.map()comPromise.all:
1async function processarUsuarios(listaIds) {
2 const promessas = listaIds.map(id => fetchUsuarioPorId(id));
3 const usuarios = await Promise.all(promessas);
4
5 console.log("Processamento concluído!");
6}- Para processamento estritamente sequencial: Utilize o loop
for...of:
1async function processarUsuariosSequencial(listaIds) {
2 for (const id of listaIds) {
3 const usuario = await fetchUsuarioPorId(id);
4 console.log(usuario.nome);
5 }
6}3. Ignorar o Tratamento de Erros (Esquecer o try...catch)
Com .then(), costumava-se encadear o .catch(). Com async/await, rejeições de Promises lançam exceções normais no JavaScript. Não tratá-las resulta no alerta de UnhandledPromiseRejection, podendo crashar o seu servidor em cenários Node.js.
O erro:
1async function buscarPerfil() {
2 // Se o fetch falhar ou retornar erro de rede, a aplicação quebra silenciosamente ou gera um uncaught error
3 const dados = await api.get('/perfil');
4 return dados;
5}A solução:
Sempre envolva fluxos suscetíveis a falhas em blocos try...catch:
1async function buscarPerfil() {
2 try {
3 const dados = await api.get('/perfil');
4 return dados;
5 } catch (erro) {
6 console.error("Falha ao carregar o perfil:", erro.message);
7 // Trate o erro graciosamente (retorne um fallback ou re-lance a exceção formatada)
8 throw new Error("Não foi possível carregar os dados no momento.");
9 }
10}4. Esquecer que uma Função async SEMPRE Retorna uma Promise
Mesmo que você retorne um valor simples (como um número ou uma string) de dentro de uma função async, o JavaScript automaticamente embrulha esse retorno dentro de uma Promise resolvida.
O erro:
1async function obterVersaoApi() {
2 return "v1.0.0";
3}
4
5function exibirVersao() {
6 // ERRO: versao será uma Promise {<fulfilled>: 'v1.0.0'}, não a string esperada!
7 const versao = obterVersaoApi();
8 console.log(`Versão atual: ${versao}`);
9}A solução:
Quem consome uma função async deve obrigatoriamente usar await ou .then():
1async function exibirVersao() {
2 const versao = await obterVersaoApi();
3 console.log(`Versão atual: ${versao}`);
4}5. Usar return await Desnecessariamente
Embora funcione sem quebrar a aplicação, fazer return await na última linha de uma função async é redundante na maioria dos casos e adiciona micro-passos desnecessários na pilha da Call Stack.
O erro:
1async function buscarDados() {
2 // O 'await' aqui é redundante, pois a função já é async e resolverá a Promise automaticamente ao retornar
3 return await fetch('https://api.cleanstack.com.br/dados');
4}A solução:
Retorne a Promise diretamente. O chamador da função buscarDados() é quem resolverá o resultado final:
1async function buscarDados() {
2 return fetch('https://api.cleanstack.com.br/dados');
3}Exceção à regra: Se você estiver dentro de um bloco try...catch e quiser capturar o erro da Promise dentro da própria função antes de retornar, aí sim o return await é necessário.
Conclusão
O ecossistema async/await simplifica drasticamente a legibilidade do código JavaScript, mas exige atenção no gerenciamento de concorrência e tratamento de exceções. Evitando esses 5 erros clássicos, sua aplicação se tornará consideravelmente mais rápida, robusta e escalável.