Programação Assíncrona em JavaScript: Guia Completo

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 single-thread com um loop de eventos (Event Loop) não bloqueante. Isso significa que apenas uma operação é executada por vez, mas graças à assincronicidade, não precisamos esperar a conclusão de tarefas lentas (leitura de arquivo, requisição à API, timer) e podemos continuar executando outro código. Neste artigo, abordaremos todos os conceitos-chave da programação assíncrona no ambiente Node.js, desde callbacks até a sintaxe moderna async/await.



A programação assíncrona permite criar aplicações server-side de alto desempenho que processam milhares de requisições sem bloquear a thread principal. Compreender esse paradigma é uma habilidade obrigatória para qualquer desenvolvedor JavaScript.



1. Funções Callback e o problema do Callback Hell



Historicamente, o primeiro mecanismo de assincronicidade em JavaScript foram os callbacks — funções que são chamadas após a conclusão de uma operação assíncrona.



Exemplo de um callback simples



const fs = require('fs');

// Leitura assíncrona de arquivofs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error('Erro de leitura:', err); return; } console.log('Conteúdo do arquivo:', data);});

console.log('Esta mensagem aparecerá antes do conteúdo do arquivo');


O problema surge quando precisamos executar várias operações assíncronas sequenciais. O aninhamento de callbacks cresce e o código se torna ilegível — esse fenômeno é chamado de "Callback Hell" ou "Inferno dos Callbacks".



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;            // Processamento dos três arquivos            console.log(data1 + data2 + data3);        });    });});


Esse código é difícil de manter, testar e depurar. A solução para esse problema veio com o surgimento das Promises.



2. Promise: livrando-se do Callback Hell



Promise (promessa) é um objeto que representa o resultado de uma operação assíncrona: execução bem-sucedida (resolve) ou erro (reject). A Promise permite encadear chamadas, tornando o código mais plano e legível.



Criação e uso de Promise



// Função que retorna uma Promiseconst readFilePromise = (filename) => {    return new Promise((resolve, reject) => {        fs.readFile(filename, 'utf8', (err, data) => {            if (err) reject(err);            else resolve(data);        });    });};

// UsoreadFilePromise('file1.txt') .then(data => { console.log('Arquivo lido:', data); return readFilePromise('file2.txt'); }) .then(data => { console.log('Segundo arquivo:', data); }) .catch(err => { console.error('Erro:', err); });


Métodos Promise.all e Promise.race



Para execução paralela de várias operações assíncronas, existem métodos estáticos úteis:



  • Promise.all() — aguarda a conclusão de todas as promises. Se pelo menos uma falhar, todo o Promise.all entra em estado rejected.
  • Promise.race() — retorna o resultado da primeira promise concluída (sucesso ou erro).
  • Promise.allSettled() — aguarda a conclusão de todas as promises, retornando os resultados de cada uma (sucesso ou erro).


const promise1 = readFilePromise('file1.txt');const promise2 = readFilePromise('file2.txt');const promise3 = readFilePromise('file3.txt');

Promise.all([promise1, promise2, promise3]) .then(results => { console.log('Todos os arquivos lidos:', results); }) .catch(err

Blogs

Book Recommendations