Programação Assíncrona
Aula 6 de 8
Callbacks
// setTimeout
setTimeout(() => {
console.log('Executado após 2 segundos');
}, 2000);
// setInterval
const intervalo = setInterval(() => {
console.log('A cada 1 segundo');
}, 1000);
// Parar intervalo
setTimeout(() => clearInterval(intervalo), 5000);
// Callback Hell (evitar!)
function buscarUsuario(id, callback) {
setTimeout(() => {
callback({ id, nome: 'João' });
}, 1000);
}
function buscarPedidos(usuarioId, callback) {
setTimeout(() => {
callback([{ id: 1, total: 150 }, { id: 2, total: 80 }]);
}, 1000);
}
buscarUsuario(1, (usuario) => {
buscarPedidos(usuario.id, (pedidos) => {
// callback hell - difícil de ler e manter
console.log(usuario, pedidos);
});
});
Promises
// Criar Promise
const promessa = new Promise((resolve, reject) => {
const sucesso = true;
setTimeout(() => {
if (sucesso) {
resolve('Operação concluída!');
} else {
reject(new Error('Algo deu errado'));
}
}, 1000);
});
// Consumir Promise
promessa
.then(resultado => console.log(resultado))
.catch(erro => console.error(erro))
.finally(() => console.log('Finalizado'));
Refatorando Callbacks
function buscarUsuario(id) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id, nome: 'João' }), 1000);
});
}
function buscarPedidos(usuarioId) {
return new Promise((resolve) => {
setTimeout(() => resolve([
{ id: 1, total: 150 },
{ id: 2, total: 80 }
]), 1000);
});
}
// Promise chain
buscarUsuario(1)
.then(usuario => buscarPedidos(usuario.id))
.then(pedidos => console.log(pedidos))
.catch(erro => console.error(erro));
Métodos Estáticos
// Promise.all - aguarda TODAS (falha rápida)
const p1 = fetch('/api/usuario');
const p2 = fetch('/api/produtos');
const p3 = fetch('/api/config');
Promise.all([p1, p2, p3])
.then(respostas => Promise.all(respostas.map(r => r.json())))
.then(([usuario, produtos, config]) => {
console.log('Tudo carregado:', usuario, produtos, config);
});
// Promise.allSettled - aguarda TODAS (sem falha rápida)
Promise.allSettled([p1, p2, p3])
.then(resultados => {
resultados.forEach(r => {
if (r.status === 'fulfilled') console.log('OK:', r.value);
if (r.status === 'rejected') console.log('FALHOU:', r.reason);
});
});
// Promise.race - primeira a resolver/rejeitar vence
Promise.race([
fetch('/api/dados'),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
)
]);
// Promise.any - primeira a resolver (ignora rejeições)
Promise.any([buscarUsuario(1), buscarUsuario(2)])
.then(primeiro => console.log('Primeiro a responder:', primeiro));
Async/Await
async function carregarDados() {
try {
const usuario = await buscarUsuario(1);
const pedidos = await buscarPedidos(usuario.id);
console.log(usuario, pedidos);
} catch (erro) {
console.error('Erro:', erro);
}
}
carregarDados();
// Execução paralela com async/await
async function carregarParalelo() {
try {
const [usuario, produtos] = await Promise.all([
buscarUsuario(1),
fetch('/api/produtos').then(r => r.json())
]);
return { usuario, produtos };
} catch (erro) {
console.error('Falha ao carregar:', erro);
throw erro;
}
}
// Top-level await (módulos)
// const dados = await fetch('/api/config').then(r => r.json());
Exemplo Prático com fetch
async function buscarDadosGitHub(usuario) {
const url = `https://api.github.com/users/${usuario}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log(`Usuário: ${data.login}`);
console.log(`Repositórios públicos: ${data.public_repos}`);
return data;
} catch (erro) {
console.error('Falha na requisição:', erro.message);
throw erro;
}
}
// Opções da requisição
async function enviarDados(url, dados) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify(dados)
});
if (!response.ok) throw new Error('Erro na requisição');
return response.json();
}
Lab: Buscador de CEP
Crie uma função assíncrona que busca endereço por CEP usando a API ViaCEP. Trate erros e timeout.
node buscar-cep.js
async function buscarCEP(cep) {
const cepLimpo = cep.replace(/\D/g, '');
if (cepLimpo.length !== 8) throw new Error('CEP inválido');
const url = `https://viacep.com.br/ws/${cepLimpo}/json/`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(url, { signal: controller.signal });
const data = await response.json();
if (data.erro) throw new Error('CEP não encontrado');
console.log(`Logradouro: ${data.logradouro}`);
console.log(`Bairro: ${data.bairro}`);
console.log(`Cidade: ${data.localidade}/${data.uf}`);
return data;
} catch (erro) {
if (erro.name === 'AbortError') throw new Error('Timeout na requisição');
throw erro;
} finally {
clearTimeout(timeout);
}
}
buscarCEP('01310-100').catch(console.error);
Async/await tornou o código assíncrono legível como síncrono. Use
Promise.all()para paralelismo etry/catchsempre.