O que é Processamento Assíncrono
Processamento assíncrono é um mecanismo que permite continuar outras operações sem esperar por operações demoradas (leitura de arquivos, chamadas de API, timers, etc.).
flowchart LR
subgraph Sync["Processamento Síncrono (espera sequencial)"]
S1["Tarefa 1"] --> S1C["Concluída"] --> S2["Tarefa 2"] --> S2C["Concluída"] --> S3["Tarefa 3"] --> S3C["Concluída"]
end
flowchart TB
subgraph Async["Processamento Assíncrono (execução concorrente)"]
A1["Tarefa 1 Início"]
A2["Tarefa 2 Início"]
A3["Tarefa 3 Início"]
A1C["Tarefa 1 Concluída"]
A2C["Tarefa 2 Concluída"]
A3C["Tarefa 3 Concluída"]
end
Event Loop
JavaScript é single-threaded, mas realiza processamento assíncrono através do event loop.
flowchart TB
CallStack["Call Stack<br/>(executa código síncrono)"]
EventLoop["Event Loop<br/>(retira da fila quando a call stack está vazia)"]
Microtask["Microtask Queue<br/>(Promise, queueMicrotask)<br/>★ Prioridade: Alta"]
Macrotask["Macrotask Queue<br/>(setTimeout, I/O)<br/>Prioridade: Baixa"]
CallStack <--> EventLoop
EventLoop --> Microtask
EventLoop --> Macrotask
Exemplo de Ordem de Execução
console.log('1'); // Síncrono
setTimeout(() => console.log('2'), 0); // Macrotask
Promise.resolve().then(() => console.log('3')); // Microtask
console.log('4'); // Síncrono
// Saída: 1, 4, 3, 2
Callback
É o padrão assíncrono mais básico.
// Exemplo de callback hell
fs.readFile('file1.txt', (err, data1) => {
if (err) throw err;
fs.readFile('file2.txt', (err, data2) => {
if (err) throw err;
fs.readFile('file3.txt', (err, data3) => {
if (err) throw err;
console.log(data1, data2, data3);
});
});
});
Problemas:
- Aninhamento profundo (callback hell)
- Tratamento de erros complexo
- Baixa legibilidade
Promise
É um objeto que representa a eventual conclusão (ou falha) de uma operação assíncrona.
// Criação de Promise
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Sucesso!');
} else {
reject(new Error('Falhou'));
}
}, 1000);
});
// Uso de Promise
myPromise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log('Concluído'));
Promise Chain
fetchUser(userId)
.then(user => fetchPosts(user.id))
.then(posts => fetchComments(posts[0].id))
.then(comments => {
console.log(comments);
})
.catch(error => {
console.error('Error:', error);
});
Promise.all / Promise.race
// Promise.all: Espera todos completarem
const results = await Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]);
// → [user1, user2, user3]
// Promise.race: Retorna o primeiro a completar
const fastest = await Promise.race([
fetchFromServer1(),
fetchFromServer2()
]);
// Promise.allSettled: Obtém todos os resultados (incluindo falhas)
const results = await Promise.allSettled([
fetchUser(1),
fetchUser(999) // Usuário inexistente
]);
// → [{status: 'fulfilled', value: user1}, {status: 'rejected', reason: Error}]
async/await
É um açúcar sintático para escrever Promises de forma mais intuitiva.
// Função async
async function fetchUserData(userId) {
try {
const user = await fetchUser(userId);
const posts = await fetchPosts(user.id);
const comments = await fetchComments(posts[0].id);
return { user, posts, comments };
} catch (error) {
console.error('Error:', error);
throw error;
}
}
Execução Paralela
// Execução sequencial (lenta)
async function sequential() {
const user1 = await fetchUser(1); // 1 segundo
const user2 = await fetchUser(2); // 1 segundo
const user3 = await fetchUser(3); // 1 segundo
// Total: 3 segundos
}
// Execução paralela (rápida)
async function parallel() {
const [user1, user2, user3] = await Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]);
// Total: ~1 segundo
}
Tratamento de Erros
try/catch
async function fetchData() {
try {
const data = await riskyOperation();
return data;
} catch (error) {
if (error.code === 'NOT_FOUND') {
return null;
}
throw error; // Re-throw
}
}
Wrapper de Erro
// Padrão que retorna erro como array
async function safeAsync(promise) {
try {
const data = await promise;
return [null, data];
} catch (error) {
return [error, null];
}
}
// Uso
const [error, user] = await safeAsync(fetchUser(id));
if (error) {
console.error('Failed to fetch user:', error);
return;
}
console.log(user);
Concorrência e Paralelismo
flowchart LR
subgraph Concurrent["Concorrência (Concurrent)"]
direction LR
Note1["Múltiplas tarefas executam sobrepondo-se no tempo<br/>(realizável mesmo em single-thread)"]
end
subgraph Parallel["Paralelismo (Parallel)"]
direction LR
Note2["Múltiplas tarefas executam simultaneamente<br/>(requer multi-thread/multi-core)"]
end
Processamento Paralelo no Node.js
// Worker Threads
const { Worker } = require('worker_threads');
function runCPUIntensiveTask(data) {
return new Promise((resolve, reject) => {
const worker = new Worker('./heavy-task.js', {
workerData: data
});
worker.on('message', resolve);
worker.on('error', reject);
});
}
Iteração Assíncrona
// for await...of
async function* generateUsers() {
for (let id = 1; id <= 3; id++) {
yield await fetchUser(id);
}
}
for await (const user of generateUsers()) {
console.log(user);
}
// AsyncIterator
const stream = fs.createReadStream('large-file.txt');
for await (const chunk of stream) {
console.log(chunk);
}
Antipadrões
Uso Excessivo de await
// Mau exemplo: await desnecessário
async function bad() {
return await fetchData(); // await é desnecessário
}
// Bom exemplo
async function good() {
return fetchData(); // Retorna Promise diretamente
}
Armadilha da Execução Sequencial
// Mau exemplo: Execução sequencial de processos independentes
const user = await fetchUser(id);
const config = await fetchConfig(); // Não depende de user
// Bom exemplo: Execução paralela
const [user, config] = await Promise.all([
fetchUser(id),
fetchConfig()
]);
Resumo
A programação assíncrona é essencial para o desenvolvimento moderno de JavaScript. Ela evoluiu de callbacks para Promise e async/await, permitindo escrever código mais legível e manutenível. Ao entender o mecanismo do event loop e realizar tratamento de erros adequado e execução paralela, você pode implementar processamento assíncrono eficiente.
← Voltar para a lista