JavaScript Assíncrono: Callbacks, Promises e Async/Await

Imagine que você precise processar diversas tarefas ao mesmo tempo em seu código JavaScriptIntrodução ao JavaScript e Configuração do AmbienteIntrodução ao JavaScript e Configuração do AmbienteDescubra neste tutorial narrativo como configurar seu ambiente de desenvolvimento e começar a programar em JavaScript de maneira prática e eficiente., como ler arquivos, carregar dados ou executar certas operações que demandam um tempo maior de resposta. Nesses cenários, a programação assíncrona desempenha um papel fundamental para que seu código não fique “travado” enquanto espera uma operação terminar. Para lidar com a assincronicidade no JavaScriptIntrodução ao JavaScript e Configuração do AmbienteIntrodução ao JavaScript e Configuração do AmbienteDescubra neste tutorial narrativo como configurar seu ambiente de desenvolvimento e começar a programar em JavaScript de maneira prática e eficiente., contamos com três recursos principais ao longo da evolução da linguagem: Callbacks, Promises e Async/Await.

Motivação e Conceito Básico🔗

Em sua forma mais simples, o JavaScriptIntrodução ao JavaScript e Configuração do AmbienteIntrodução ao JavaScript e Configuração do AmbienteDescubra neste tutorial narrativo como configurar seu ambiente de desenvolvimento e começar a programar em JavaScript de maneira prática e eficiente. executa instruções de maneira síncrona: uma linha após a outra, bloqueando o fluxo até completar a tarefa atual. Porém, no desenvolvimento de aplicações mais complexas, precisamos disparar eventos e reagir a respostas que podem chegar a qualquer momento, sem travar o restante do código.

A partir disso, surgem as funçõesFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. de callback, as Promises e o async/await, cada qual oferecendo mecanismos mais fluídos para lidar com operações que só terminam depois de um certo tempo (por exemplo, leitura de arquivos, requisições a servidores, entre outros).

Callbacks🔗

O callback foi o primeiro padrão difundido para lidar com assincronismo no JavaScriptIntrodução ao JavaScript e Configuração do AmbienteIntrodução ao JavaScript e Configuração do AmbienteDescubra neste tutorial narrativo como configurar seu ambiente de desenvolvimento e começar a programar em JavaScript de maneira prática e eficiente.. Um callback nada mais é do que passar uma funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. como argumento para outra funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. e chamá-la quando a operação estiver concluída. Assim, o fluxo principal não fica bloqueado.

Exemplo de Callback

function pegarDados(callback) {
  setTimeout(function() {
    // Simulação de uma operação demorada
    const dados = { nome: "Maria", idade: 30 };
    callback(dados);
  }, 2000);
}
function exibirUsuario(usuario) {
  console.log(`Usuário: ${usuario.nome}, Idade: ${usuario.idade}`);
}
// Chamando a função com callback
pegarDados(exibirUsuario);

O que acontece aqui?

1. Criamos a funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. pegarDados que recebe um parâmetroFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. callback.

2. Simulamos uma operação demorada com setTimeout.

3. Após 2 segundos, chamamos callback(dados), enviando o objetoFundamentos de Arrays e ObjetosFundamentos de Arrays e ObjetosDomine arrays e objetos em JavaScript com este tutorial narrativo. Aprenda a utilizar métodos e exemplos práticos para aprimorar seu desenvolvimento web. dados.

4. A funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. exibirUsuario é usada como callback para exibir o resultado no consoleDebugging e Ferramentas de Desenvolvimento do NavegadorDebugging e Ferramentas de Desenvolvimento do NavegadorAprenda a depurar código JavaScript com as Ferramentas do Navegador. Use console, breakpoints e debugger para solucionar bugs de forma prática..

Problemas comuns: Callback Hell

Por mais úteis que sejam, os callbacks podem gerar uma aninhamentoPré-processadores (SASS/SCSS): Variáveis, Mixins, NestingPré-processadores (SASS/SCSS): Variáveis, Mixins, NestingAprenda a manter seu CSS de forma otimizada com SASS/SCSS utilizando variáveis, mixins e nesting para um código limpo e produtivo. excessivo quando precisamos executar várias operações assíncronas em sequência. Esse efeito é conhecido como Callback Hell:

realizarOperacaoA(function(resultadoA) {
  realizarOperacaoB(resultadoA, function(resultadoB) {
    realizarOperacaoC(resultadoB, function(resultadoC) {
      // E assim por diante...
    });
  });
});

Esse código se torna difícil de manter e ler, motivando a criação de novas abordagens para o fluxo assíncrono, como as Promises.

Promises🔗

Para resolver a complexidade dos callbacks encadeados, foram introduzidas as Promises. Uma Promise representa o resultado futuro de uma operação assíncrona e pode estar em um dos seguintes estados:

  • pending (pendente)
  • fulfilled (resolvida com sucesso)
  • rejected (rejeitada por algum erro)

Criando e Consumindo Promises

A Promise é criada usando o construtor new Promise, que recebe uma funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. executor com dois parâmetrosFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas.: resolve e reject.

function pegarDadosPromise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const sucesso = true; // Simulando se a operação deu certo ou não
      if (sucesso) {
        resolve({ nome: "Carlos", idade: 25 });
      } else {
        reject("Erro ao buscar dados");
      }
    }, 2000);
  });
}

Para consumir essa Promise, utilizamos seus métodosClasses e Herança em ES6+Classes e Herança em ES6+Aprenda a dominar classes e herança em ES6+: escreva códigos JavaScript claros e eficientes com métodos, getters e setters. encadeáveis:

  • .then(...) para tratar o sucesso (fulfilled).
  • .catch(...) para tratar a falha (rejected).
  • .finally(...) (opcional) para executar algo ao final, independentemente de sucesso ou falha.
pegarDadosPromise()
  .then((usuario) => {
    console.log("Dados do usuário:", usuario);
  })
  .catch((erro) => {
    console.error("Ocorreu um erro:", erro);
  })
  .finally(() => {
    console.log("Final da operação.");
  });

Vantagens das Promises:

1. Encadeamento: Podemos montar uma sequência de .then(...) para tratar operações em série.

2. Tratamento de erros: Um único .catch(...) pode capturar erros de toda a cadeia.

Encadeamento de Promises

pegarDadosPromise()
  .then((usuario) => {
    console.log("Usuário 1:", usuario);
    return pegarDadosPromise(); // segunda chamada
  })
  .then((usuario2) => {
    console.log("Usuário 2:", usuario2);
    // Podemos retornar outra Promise, ou valor simples
  })
  .catch((erro) => {
    console.error("Erro na sequência:", erro);
  });

Async/Await🔗

O async/await é uma evolução na forma de lidar com Promises e tornar o código assíncrono mais legível e fluído, se aproximando de um estiloRelação entre HTML e CSSRelação entre HTML e CSSDescubra como HTML e CSS trabalham juntos para criar páginas web esteticamente agradáveis e bem estruturadas, facilitando a manutenção e o desempenho. síncrono.

Funções Assíncronas

Para usar await, é preciso que a funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. seja assíncrona: basta prefixar async antes do nome da funçãoFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas.. A palavra-chave await pausa a execução até que uma Promise seja resolvida (ou rejeitada), simplificando drasticamente o encadeamento de operações.

async function exibirDadosAsync() {
  try {
    const usuario = await pegarDadosPromise();
    console.log("Async/Await - Usuário:", usuario);
  } catch (erro) {
    console.error("Async/Await - Erro:", erro);
  } finally {
    console.log("Async/Await - Final da operação.");
  }
}
exibirDadosAsync();

Fluxo Sequencial com Async/Await

Se você quer realizar várias operações em sequência, o async/await torna o código muito mais simples em comparação aos .then() encadeados:

async function carregarVariosDados() {
  try {
    const usuario1 = await pegarDadosPromise();
    const usuario2 = await pegarDadosPromise();
    console.log("Usuário 1:", usuario1);
    console.log("Usuário 2:", usuario2);
  } catch (erro) {
    console.error("Erro ao carregar dados:", erro);
  }
}

Vantagens do Async/Await:

  • Código mais limpo: Fica mais fácil ler e manter.
  • Tratamento de erros simplificado: Basta usar try...catch.
  • Fluxo sequencial muito mais intuitivo.

Resumo em Tabela🔗

RecursoPrincipais CaracterísticasExemplo Básico
CallbackFunção passada como argumento; pode gerar Callback Hell<pre><code>realizarOp((result) =&gt; { console.log(result); });</code></pre>
PromiseEncadeamento de .then(), .catch(), .finally()<pre><code>pegarDadosPromise().then(...).catch(...)</code></pre>
Async/AwaitSintaxe mais limpa e próxima ao fluxo síncrono<pre><code>async function exemplo() { try { const res = await minhaPromise();} catch(err) { ... } }</code></pre>

Dicas e Boas Práticas🔗

1. Trate sempre os erros: Utilize try...catch ou .catch(...) para evitar travar a aplicação.

2. Não bloqueie a UI: Faça bom uso de funçõesFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. de retorno e processos assíncronos para proporcionar fluidez na interação do usuário.

3. Async/Await e Promises juntos: Em alguns cenários, a combinação de ambos é desejável, especialmente quando aguardamos múltiplas Promises com métodosClasses e Herança em ES6+Classes e Herança em ES6+Aprenda a dominar classes e herança em ES6+: escreva códigos JavaScript claros e eficientes com métodos, getters e setters. como Promise.all() ou Promise.race().

4. Organize o código: Evite o crescimento desordenado de funções encadeadas; refatore em funçõesFunções e Escopo no JavaScriptFunções e Escopo no JavaScriptAprenda a utilizar funções e escopos em JavaScript com nosso guia prático. Melhore sua organização de código e evolua seus projetos com boas práticas. menores e reutilizáveis.

Conclusão🔗

A evolução de Callbacks para Promises e, finalmente, para Async/Await oportunidade de escrever códigos assíncronos mais limpos e organizados. Cada recurso tem sua utilidade em diferentes cenários, cabendo a você escolher a melhor abordagem. Com esse conhecimento, você estará melhor preparado para lidar com situações em que precise executar tarefas em paralelo ou em sequência sem travar sua aplicação.

No próximo passo do seu aprendizado, explore brevemente como cada um desses recursos se integra com outras funcionalidades do JavaScriptIntrodução ao JavaScript e Configuração do AmbienteIntrodução ao JavaScript e Configuração do AmbienteDescubra neste tutorial narrativo como configurar seu ambiente de desenvolvimento e começar a programar em JavaScript de maneira prática e eficiente. para manipular dados e fornecer respostas de forma elegante ao usuário. Seguindo essas boas práticas, o desenvolvimento de aplicações se torna mais previsível, robusto e fácil de manter.

Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.

Referências🔗

Compartilhar artigo

Artigos Relacionados