404 Not Found

404 Not Found


nginx

Programação Assíncrona em JavaScript

JavaScript é single-threaded — só consegue fazer uma coisa por vez. Mas se uma requisição de rede leva 3 segundos, a página deve congelar por 3 segundos? Claro que não. A programação assíncrona resolve isso: em vez de esperar, você pega uma senha e volta quando estiver pronto. Como um sistema de fila de restaurante — você não fica na porta da cozinha, senta e espera sua senha ser chamada.


Síncrono vs Assíncrono

Síncrono: O código executa linha por linha — a próxima linha espera a atual terminar. Como ficar na fila — você espera até que a pessoa à sua frente termine.

Assíncrono: Certas operações (requisições de rede, temporizadores, E/S de arquivo) iniciam sem bloquear o código subsequente. Quando terminam, você é notificado via callback ou Promise.

HTML
<script>
console.log('1');
setTimeout(function() {
  console.log('2');
}, 1000);
console.log('3');
</script>

A ordem de saída é 1 → 3 → 2. setTimeout é assíncrono — seu callback executa após 1 segundo sem bloquear console.log('3').


Callbacks

Callbacks são o padrão assíncrono mais básico — passe uma função como argumento, e ela será chamada quando a operação assíncrona completar.

Exemplo: Uso Básico de Callback

HTML
<div id="output" style="padding: 10px; border: 1px solid #ccc;"></div>

<script>
const output = document.getElementById('output');

function buscarDados(callback) {
  output.textContent = 'Carregando...';
  setTimeout(function() {
    callback('Dados carregados!');
  }, 2000);
}

buscarDados(function(dados) {
  output.textContent = dados;
});
</script>
▶ Experimente

Callback Hell

Quando operações assíncronas dependem umas das other em sequência, callbacks ficam cada vez mais aninhados — este é o infame "Callback Hell."

HTML
<script>
obterUsuario(function(usuario) {
  obterPedidos(usuario.id, function(pedidos) {
    obterDetalhePedido(pedidos[0].id, function(detalhe) {
      obterItens(detalhe.itemId, function(itens) {
        console.log('4 níveis de profundidade — adicione mais complexidade e fica ilegível');
      });
    });
  });
});
</script>
💡 Callback hell parece uma "pirâmide horizontal" — difícil de ler e manter. Promises foram inventadas para resolver isso.


Promise

Uma Promise é um objeto que representa o resultado eventual de uma operação assíncrona. Tem três estados:

Estado Descrição
pending Em andamento, sem resultado ainda
fulfilled Completado com sucesso, resultado disponível
rejected Falhou, erro disponível

Quando uma Promise transiciona de pending para fulfilled ou rejected, ela nunca volta atrás — como uma flecha uma vez disparada, não pode ser chamada de volta.

Criando uma Promise

HTML
<script>
const promise = new Promise(function(resolve, reject) {
  // operação assíncrona
  // chame resolve(resultado) em caso de sucesso
  // chame reject(erro) em caso de falha
});
</script>

then / catch / finally

HTML
<script>
promise
  .then(function(resultado) { console.log(resultado); })   // executa em caso de sucesso
  .catch(function(erro) { console.error(erro); })          // executa em caso de falha
  .finally(function() { console.log('Concluído'); });       // executa sempre
</script>

Exemplo: Simulando uma Requisição com Promise

HTML
<button id="loadBtn">Carregar Dados</button>
<div id="output" style="padding: 10px; border: 1px solid #ccc; margin-top: 10px;"></div>

<script>
const btn = document.getElementById('loadBtn');
const output = document.getElementById('output');

function buscarUsuario() {
  return new Promise(function(resolve, reject) {
    output.textContent = 'Carregando...';
    setTimeout(function() {
      const sucesso = true;
      if (sucesso) {
        resolve({ nome: 'Alice', idade: 25 });
      } else {
        reject(new Error('Falha no carregamento'));
      }
    }, 1500);
  });
}

btn.addEventListener('click', function() {
  buscarUsuario()
    .then(function(usuario) {
      output.textContent = 'Nome: ' + usuario.nome + ', Idade: ' + usuario.idade;
    })
    .catch(function(err) {
      output.textContent = 'Erro: ' + err.message;
    })
    .finally(function() {
      console.log('Requisição concluída (sucesso ou falha)');
    });
});
</script>
▶ Experimente

Encadeamento

then em si retorna uma Promise, então você pode encadear chamadas — callback hell vira uma linha reta.

HTML
<script>
buscarUsuario()
  .then(function(usuario) { return buscarPedidos(usuario.id); })
  .then(function(pedidos) { return buscarDetalhe(pedidos[0].id); })
  .then(function(detalhe) { console.log(detalhe); })
  .catch(function(err) { console.error(err); });
</script>
💡 Um único catch no final do encadeamento captura erros de qualquer etapa — você não precisa de um catch após cada then.


async / await

async/await é açúcar sintático sobre Promisses — faz código assíncrono parecer síncrono, melhorando muito a legibilidade.

Exemplo: Reescrevendo a Requisição Acima com async/await

HTML
<button id="loadBtn">Carregar Dados</button>
<div id="output" style="padding: 10px; border: 1px solid #ccc; margin-top: 10px;"></div>

<script>
const btn = document.getElementById('loadBtn');
const output = document.getElementById('output');

function buscarUsuario() {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({ nome: 'Bob', idade: 30 });
    }, 1500);
  });
}

btn.addEventListener('click', async function() {
  try {
    output.textContent = 'Carregando...';
    const usuario = await buscarUsuario();
    output.textContent = 'Nome: ' + usuario.nome + ', Idade: ' + usuario.idade;
  } catch (err) {
    output.textContent = 'Erro: ' + err.message;
  } finally {
    console.log('Requisição concluída');
  }
});
</script>
▶ Experimente
💡 Comparado com callbacks, async/await transforma "pegar uma senha e esperar" em "ficar na fila sem sair" — o fluxo do código é reto e a legibilidade vai lá em cima.

Tratamento de Erros

async/await usa try/catch para tratamento de erros — o mesmo padrão usado com código síncrono.

HTML
<script>
async function carregarTudo() {
  try {
    const usuario = await buscarUsuario();
    const pedidos = await buscarPedidos(usuario.id);
    console.log(pedidos);
  } catch (err) {
    console.error('Algo deu errado:', err);
  }
}
</script>

Promise.all e Promise.race

Método Descrição
Promise.all([p1, p2, p3]) Sucesso apenas se todas tiverem sucesso; falha assim que uma falhar
Promise.race([p1, p2, p3]) Usa o resultado da primeira a resolver (sucesso ou falha)

Exemplo: Requisições Concorrentes com Promise.all

HTML
<button id="loadAll">Carregar Concorrentemente</button>
<div id="output" style="padding: 10px; border: 1px solid #ccc; margin-top: 10px;"></div>

<script>
const btn = document.getElementById('loadAll');
const output = document.getElementById('output');

function atraso(ms, valor) {
  return new Promise(function(resolve) {
    setTimeout(function() { resolve(valor); }, ms);
  });
}

btn.addEventListener('click', async function() {
  output.textContent = 'Carregando...';

  const resultados = await Promise.all([
    atraso(1000, 'Dados do Usuário'),
    atraso(1500, 'Dados de Pedidos'),
    atraso(800, 'Dados de Configuração')
  ]);

  output.textContent = 'Tudo carregado:\n' + resultados.join(' | ');
});

const raceBtn = document.createElement('button');
raceBtn.textContent = 'Carregamento Corrida';
document.body.appendChild(raceBtn);

raceBtn.addEventListener('click', async function() {
  const maisRapido = await Promise.race([
    atraso(1000, 'Fonte A (1s)'),
    atraso(500, 'Fonte B (0.5s)'),
    atraso(800, 'Fonte C (0.8s)')
  ]);
  output.textContent = 'Mais rápido: ' + maisRapido;
});
</script>
▶ Experimente
💡 Promise.all é como um jantar em grupo — todos devem chegar antes de comer. Promise.race é como uma corrida — quem terminar primeiro ganha. Use all para requisições independentes para acelerar, e race quando tiver múltiplas fontes espelho e quiser a mais rápida.


📖 Resumo

  1. Código síncrono bloqueia execução subsequente; código assíncrono não — single-threaded ainda consegue "fazer várias coisas"
  2. Callbacks são o padrão assíncrono mais básico; aninhamento profundo cria callback hell
  3. Promise tem três estados: pending → fulfilled ou pending → rejected — transições de estado são irreversíveis
  4. then/catch/finally consomem Promisses; encadeamento resolve callback hell
  5. async/await é açúcar sintático sobre Promises; await só pode ser usado dentro de funções async
  6. Promise.all espera todas terem sucesso; Promise.race pega a primeira a resolver

❓ Perguntas Frequentes

P: await pode ser usado em uma função comum? R: Não. await só pode ser usado dentro de uma função async. Usar await em uma função comum causa erro de sintaxe. await de nível superior é suportado em módulos, mas o suporte do navegador varia.

P: O que acontece se uma das Promises em Promise.all falhar? R: Promise.all rejeita imediatamente com o primeiro erro. Outras Promises ainda executam, mas seus resultados são ignorados. Se precisar de "todas resolvidas independentemente do resultado," use Promise.allSettled.

P: O que uma função async retorna? R: Uma função async sempre retorna uma Promise. Mesmo que você faça return 42, na verdade retorna Promise.resolve(42). Então você pode usar .then() para consumir o resultado.

📝 Atividades

  1. Básico: Use Promise + setTimeout para simular um atraso de 2 segundos, depois exiba "Concluído" em caso de sucesso.
  2. Intermediário: Reescreva o acima com async/await e adicione tratamento de erros com try/catch.
  3. Desafio: Use Promise.all para disparar 3 requisições simuladas com atrasos diferentes (1s/2s/3s) concorrentemente, depois calcule e exiba o tempo total decorrido quando todas completarem.
100%