De setTimeout a Promise.all — entenda programação assíncrona de verdade com exemplos práticos e boas práticas.
Em JavaScript, algumas tarefas demoram para terminar. O JS não "trava" esperando — ele continua executando e resolve depois.
Buscar dados de uma API
Ler arquivo do sistema
Timers e delays
Consultas a banco de dados
console.log("1");
console.log("2");
console.log("3");
// 1, 2, 3
console.log("Início");
setTimeout(() => {
console.log("Demorou...");
}, 2000);
console.log("Fim");
Início
Fim
Demorou... ← aparece depois de 2 segundos
Uma Promise (promessa) é um objeto que representa o resultado de uma operação assíncrona — algo que ainda não aconteceu, mas vai acontecer no futuro.
const minhaPromise = new Promise((resolve, reject) => {
// tarefa assíncrona aqui
// resolve(valor) → sucesso
// reject(erro) → falha
});
const promessa = new Promise((resolve, reject) => {
const sucesso = true;
if (sucesso) {
resolve("Deu certo! ✔");
} else {
reject("Deu erro! ✘");
}
});
promessa
.then(res => console.log(res)) // "Deu certo! ✔"
.catch(err => console.log(err)); // caso rejeite
function buscarUsuario() {
return new Promise(resolve => {
setTimeout(() => {
resolve({ nome: "Igor", idade: 25 });
}, 2000);
});
}
buscarUsuario().then(usuario => {
console.log(usuario);
// { nome: "Igor", idade: 25 }
});
Toda Promise passa por um destes 3 estados — e só pode mudar de pending para um dos outros dois:
| Estado | Significado | Trigger |
|---|---|---|
| pending | Ainda aguardando resultado | Estado inicial |
| fulfilled | Operação completada com sucesso | resolve() chamado |
| rejected | Operação falhou | reject() chamado |
Três métodos para consumir o resultado de uma Promise:
.then(cb)
Executado quando a Promise é resolvida (fulfilled).
.catch(cb)
Executado quando a Promise é rejeitada (rejected).
.finally(cb)
Executado sempre, independente do resultado.
minhaPromise
.then(resultado => {
console.log("Sucesso:", resultado);
})
.catch(erro => {
console.log("Erro:", erro);
})
.finally(() => {
console.log("Sempre executa!");
});
.finally() para limpar estados de loading na UI — ele roda tanto no sucesso quanto no erro.Cada .then() retorna uma nova Promise, permitindo encadear operações assíncronas em sequência — eliminando o famoso "callback hell".
// ❌ difícil de ler e manter
fazerA(() => {
fazerB(() => {
fazerC(() => {
fazerD(() => {
console.log("fim"); // pirâmide da morte
});
});
});
});
// ✅ linear e legível
fetchDados()
.then(dados => processar(dados))
.then(result => salvar(result))
.then(final => console.log(final))
.catch(err => console.log("Erro:", err));
function dobrar(n) {
return Promise.resolve(n * 2);
}
Promise.resolve(5)
.then(dobrar) // 10
.then(dobrar) // 20
.then(dobrar) // 40
.then(v => console.log(v)); // 40
O async/await é açúcar sintático sobre Promises — torna o código assíncrono mais legível, parecendo código síncrono normal.
async function
Marca uma função como assíncrona. Sempre retorna uma Promise.
await
Pausa a execução da função até a Promise resolver. Só funciona dentro de async.
async function minhaFuncao() {
return "Olá";
}
// equivale a:
function minhaFuncao() {
return Promise.resolve("Olá");
}
async function executar() {
const resultado = await Promise.resolve("Deu certo!");
console.log(resultado); // "Deu certo!"
}
executar();
function esperar(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function processo() {
console.log("Início");
await esperar(2000);
console.log("Depois de 2s");
await esperar(1000);
console.log("Depois de mais 1s");
console.log("Fim");
}
processo();
Início
Depois de 2s ← após 2 segundos
Depois de mais 1s ← após mais 1 segundo
Fim
Com async/await, trate erros com a estrutura try/catch — muito mais legível que encadear .catch().
async function buscar() {
try {
const resposta = await fetch("https://api.exemplo.com/dados");
const dados = await resposta.json();
console.log(dados);
} catch (erro) {
console.log("Erro:", erro);
} finally {
console.log("Requisição finalizada.");
}
}
| Bloco | Quando executa |
|---|---|
| try { } | Código que pode lançar erro |
| catch (e) { } | Quando um erro ocorre no try |
| finally { } | Sempre, independente de erro ou sucesso |
await fora de uma função async — causa erro de sintaxe. A exceção é o top-level await em módulos ES2022+.Métodos estáticos para lidar com múltiplas Promises ao mesmo tempo:
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(res => {
console.log(res); // [1, 2, 3]
});
async function executar() {
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
]);
console.log(user, posts, comments);
}
Promise.race([
new Promise(r => setTimeout(() => r("A"), 1000)),
new Promise(r => setTimeout(() => r("B"), 500))
]).then(console.log);
// "B" (terminou primeiro)
Promise.allSettled([
Promise.resolve("ok"),
Promise.reject("erro"),
Promise.resolve("ok também")
]).then(console.log);
// [
// { status: "fulfilled", value: "ok" },
// { status: "rejected", reason: "erro" },
// { status: "fulfilled", value: "ok também" }
// ]
| Método | O que faz | Se uma falhar |
|---|---|---|
| Promise.all | Aguarda todas terminarem | Rejeita imediatamente |
| Promise.race | Retorna a primeira que terminar | Rejeita se a primeira falhar |
| Promise.allSettled | Aguarda todas, mostra status individual | Nunca rejeita — sempre retorna tudo |
| Promise.any | Retorna a primeira que resolver | Ignora rejeições |
Promise.all para paralelizar requisições independentes — executa tudo ao mesmo tempo e espera o mais lento, muito mais rápido que await sequencial.async/await > .then()
Prefira async/await — mais legível e menos aninhado.
try/catch sempre
Sempre trate erros em funções async — sem catch silencioso.
Promise.all para paralelo
Não use await em série quando as tarefas são independentes.
Não misture estilos
Evite misturar .then() com await no mesmo bloco.
// ❌ esqueceu o await — dados é uma Promise, não o resultado!
const dados = fetchDados();
console.log(dados); // Promise { <pending> }
// ❌ sem tratamento de erro
async function f() {
const dados = await fetchDados(); // pode explodir silenciosamente
}
// ❌ await em série desnecessário (lento!)
const user = await fetchUser(); // espera 1s
const posts = await fetchPosts(); // espera mais 1s
// total: 2s! Use Promise.all (seria 1s)
// ✅ sempre await quando precisar do valor
const dados = await fetchDados();
// ✅ sempre try/catch
try {
const dados = await fetchDados();
} catch (err) {
console.log(err);
}
// ✅ Promise.all para operações independentes
const [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
]);
Um cenário realista: buscar usuário, buscar posts em paralelo e exibir tudo com tratamento de erro:
// Simula requisições assíncronas
function buscarUsuario() {
return new Promise(resolve => {
setTimeout(() => resolve({ id: 1, nome: "Igor" }), 1500);
});
}
function buscarPosts(userId) {
return new Promise(resolve => {
setTimeout(() => resolve(["Post 1", "Post 2"]), 1000);
});
}
// Função principal
async function main() {
try {
console.log("Buscando dados...");
// Busca usuário e posts em paralelo!
const [usuario, posts] = await Promise.all([
buscarUsuario(),
buscarPosts(1)
]);
console.log("Usuário:", usuario.nome);
console.log("Posts:", posts);
} catch (err) {
console.log("Erro:", err);
} finally {
console.log("Finalizado!");
}
}
main();
Buscando dados...
Usuário: Igor ← após ~1.5s (paralelo, não 2.5s!)
Posts: ["Post 1", "Post 2"]
Finalizado!
// Promise → objeto que resolve no futuro
// then/catch → forma "clássica" de consumir
// async → função que retorna Promise
// await → pausa e aguarda a Promise
// try/catch → trata erros com async/await
// Promise.all → paralelo — mais rápido!
// Promise.race → vence o primeiro
// allSettled → retorna todos, com status
setTimeout → crie Promises → use then/catch → migre para async/await → domine Promise.all → integre com fetch em APIs reais.