Programação Assíncrona em JavaScript: guia completo para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução à programação assíncrona em JavaScript

JavaScript é uma linguagem de programação single-thread com modelo de I/O não bloqueante. Isso significa que apenas uma operação é executada por vez. No entanto, graças à programação assíncrona, Node.js pode processar milhares de requisições simultaneamente sem bloquear a thread principal. Neste artigo, vamos abordar os conceitos principais de assincronia: callbacks, Promises e a sintaxe async/await.

O que é assincronia e por que ela é necessária?

Imagine que você pede uma pizza. Se você fica no balcão esperando ela ser preparada — isso é código síncrono. Tudo para. A abordagem assíncrona — você faz o pedido e cuida da sua vida. Quando a pizza fica pronta, te chamam. JavaScript funciona exatamente assim: ele não espera a conclusão de uma operação (leitura de arquivo, requisição ao servidor), mas continua executando o próximo código. Quando a operação termina, uma função especial é chamada — o callback.

Em Node.js, a assincronia é especialmente importante porque o servidor precisa atender múltiplos clientes simultaneamente. Sem ela, cada nova requisição bloquearia o funcionamento de toda a aplicação.

Código Síncrono vs Assíncrono: exemplo

Vamos considerar um exemplo simples de leitura de arquivo. A versão síncrona bloqueia a execução:

const fs = require('fs');

// Leitura síncrona — bloqueia a thread
const data = fs.readFileSync('file.txt', 'utf8');
console.log('Dados lidos:', data);
console.log('Este código será executado apenas após a leitura do arquivo');

A versão assíncrona não bloqueia:

const fs = require('fs');

// Leitura assíncrona — não bloqueia
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('Dados lidos:', data);
});

console.log('Este código será executado imediatamente, sem esperar a leitura do arquivo');

Principais formas de trabalhar com assincronia

Em JavaScript (e Node.js), existem três abordagens principais para programação assíncrona. Vamos abordá-las das mais antigas para as modernas.

1. Callback (funções de retorno)

Callback é uma função que é passada para outra função e é chamada após a conclusão de uma operação assíncrona. Este é o método mais básico e antigo.

function getUserData(userId, callback) {
  setTimeout(() => {
    const user = { id: userId, name: 'Ana' };
    callback(null, user); // primeiro argumento — erro (se houver)
  }, 1000);
}

getUserData(1, (err, user) => {
  if (err) {
    console.error('Erro:', err);
    return;
  }
  console.log('Usuário:', user.name);
});

Problema: quando há muitas operações, o código se transforma em "callback hell" — funções profundamente aninhadas, difíceis de ler e depurar.

2. Promise (Promessas)

Promise é um objeto que representa o resultado de uma operação assíncrona. Ele pode estar em um dos três estados:

  • pending (pendente) — a operação ainda não foi concluída
  • fulfilled (resolvida) — a operação foi concluída com sucesso
  • rejected (rejeitada) — a operação foi concluída com erro

Promises resolvem o problema do callback hell e tornam o código mais linear:

function getUserData(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const user = { id: userId, name: 'Ivan' };
      // resolve — sucesso, reject — erro
      resolve(user);
      // reject(new Error('Usuário não encontrado'));
    }, 1000);
  });
}

// Usando a cadeia .then()
getUserData(1)
  .then(user => {
    console.log('Usuário:', user.name);
    return user.id;
  })
  .then(id => console.log('ID:', id))
  .catch(err => console.error('Erro:', err))
  .finally(() => console.log('Operação concluída'));                

Blogs

Book Recommendations