logo CS

5 Erros que Todo Iniciante Comete com async/await em JavaScript (e Como Evitá-los)

A introdução das palavras-chave async e await no ES2017 revolucionou a forma como escrevemos código assíncrono em JavaScript. Elas nos permitiram abandonar o antigo "Callback Hell" e a sintaxe encadeada e verbosa das Promises puras, tornando o código com aparente comportamento síncrono, limpo e legível — a verdadeira essência da Clean Stack.

autor

Guilherme Braga

Publicado 07 de setembro de 2026 às 17:45

  • #JavaScript
  • #NodeJS
  • #Promisses
2 min
5 Erros que Todo Iniciante Comete com async/await em JavaScript (e Como Evitá-los)

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() com Promise.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.

Publicidade

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:

Publicidade

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.