JavaScript

Callbacks em JavaScript: O Padrão Original de Assincronismo: Do Básico ao Avançado

7 min de leitura

Callbacks em JavaScript: O Padrão Original de Assincronismo: Do Básico ao Avançado

Callbacks em JavaScript: O Padrão Original de Assincronismo O que é um Callback? Um callback é simplesmente uma função passada como argumento para outra função, que será executada posteriormente — geralmente após a conclusão de uma operação assíncrona. Em JavaScript, isso é fundamental porque a linguagem é single-threaded: operações como requisições HTTP, leitura de arquivos ou timers não podem bloquear a execução do código. O callback permite que você diga ao JavaScript: "faça isto, e quando terminar, execute essa função". Quando você compreende callbacks, você entende o núcleo da programação assíncrona em JavaScript. Mesmo com a chegada de Promises e async/await, callbacks continuam sendo o mecanismo subjacente. Se você vai dominar JavaScript profissional, precisa dessa base sólida. Callbacks Básicos e Seu Funcionamento O exemplo mais comum é o , que executa uma função após um tempo determinado: Olá, ${nome}! Aqui, a função anônima é o callback. Você passa ela para , que a armazena e a executa depois. Outro exemplo

<h2>Callbacks em JavaScript: O Padrão Original de Assincronismo</h2>

<h3>O que é um Callback?</h3>

<p>Um callback é simplesmente uma função passada como argumento para outra função, que será executada posteriormente — geralmente após a conclusão de uma operação assíncrona. Em JavaScript, isso é fundamental porque a linguagem é single-threaded: operações como requisições HTTP, leitura de arquivos ou timers não podem bloquear a execução do código. O callback permite que você diga ao JavaScript: &quot;faça isto, e quando terminar, execute essa função&quot;.</p>

<p>Quando você compreende callbacks, você entende o núcleo da programação assíncrona em JavaScript. Mesmo com a chegada de Promises e async/await, callbacks continuam sendo o mecanismo subjacente. Se você vai dominar JavaScript profissional, precisa dessa base sólida.</p>

<h3>Callbacks Básicos e Seu Funcionamento</h3>

<p>O exemplo mais comum é o <code>setTimeout</code>, que executa uma função após um tempo determinado:</p>

<pre><code class="language-javascript">function saudar(nome) {

console.log(Olá, ${nome}!);

}

setTimeout(function() {

saudar(&quot;Maria&quot;);

}, 2000); // Executa após 2 segundos</code></pre>

<p>Aqui, a função anônima é o callback. Você passa ela para <code>setTimeout</code>, que a armazena e a executa depois. Outro exemplo prático é com Array:</p>

<pre><code class="language-javascript">const numeros = [1, 2, 3, 4, 5];

const dobrados = numeros.map(function(num) {

return num * 2;

});

console.log(dobrados); // [2, 4, 6, 8, 10]</code></pre>

<p>O callback aqui é a função passada ao <code>map()</code>. Esse padrão é tão comum que você provavelmente já usou sem perceber. A função callback recebe parâmetros (no caso, <code>num</code>) que o <code>map()</code> fornece automaticamente. Isso demonstra como callbacks são flexíveis: a função que recebe o callback controla quando executá-lo e com quais argumentos.</p>

<h3>Callbacks com Operações Assíncronas Reais</h3>

<p>O verdadeiro poder dos callbacks aparece quando você trabalha com operações que levam tempo. Vamos simular uma requisição a um servidor:</p>

<pre><code class="language-javascript">function buscarUsuario(id, callback) {

setTimeout(function() {

const usuario = { id: id, nome: &quot;João&quot; };

callback(usuario);

}, 1000);

}

buscarUsuario(1, function(usuario) {

console.log(&quot;Usuário encontrado:&quot;, usuario);

});</code></pre>

<p>Aqui, <code>buscarUsuario()</code> simula uma requisição que leva 1 segundo. O callback é executado com os dados quando prontos. Em cenários reais com Node.js, você verá este padrão frequentemente:</p>

<pre><code class="language-javascript">const fs = require(&#039;fs&#039;);

fs.readFile(&#039;dados.txt&#039;, &#039;utf8&#039;, function(erro, dados) {

if (erro) {

console.log(&quot;Erro ao ler arquivo:&quot;, erro);

return;

}

console.log(&quot;Conteúdo:&quot;, dados);

});</code></pre>

<p>Aqui temos o padrão <strong>error-first callback</strong>: o primeiro parâmetro é sempre o erro (ou <code>null</code> se não houver erro), e os dados vêm depois. Esse é o padrão de facto em Node.js e você o verá em muitas bibliotecas legadas.</p>

<h3>O Problema: Callback Hell</h3>

<p>Aqui está onde callbacks mostram sua limitação. Quando você precisa fazer várias operações sequenciais, o código fica aninhado em níveis cada vez mais profundos:</p>

<pre><code class="language-javascript">fs.readFile(&#039;usuarios.json&#039;, &#039;utf8&#039;, function(erro, dados) {

if (erro) throw erro;

const usuarios = JSON.parse(dados);

fs.readFile(&#039;permissoes.json&#039;, &#039;utf8&#039;, function(erro2, dados2) {

if (erro2) throw erro2;

const permissoes = JSON.parse(dados2);

fs.writeFile(&#039;resultado.json&#039;, JSON.stringify({usuarios, permissoes}), function(erro3) {

if (erro3) throw erro3;

console.log(&quot;Arquivo salvo!&quot;);

});

});

});</code></pre>

<p>Esse &quot;callback hell&quot; ou &quot;pyramid of doom&quot; é difícil de ler, manter e debugar. O tratamento de erros fica espalhado, e rastrear o fluxo se torna complicado. É exatamente por isso que JavaScript evoluiu: Promises surgiram para resolver esse problema, seguidas por async/await.</p>

<blockquote><p><strong>Nota importante</strong>: Você deve entender callbacks profundamente não para usá-los em novo código — embora ainda apareçam em algumas APIs — mas porque muitas bibliotecas antigas os usam, e você provavelmente trabalhar com código legado.</p></blockquote>

<h3>Boas Práticas com Callbacks</h3>

<p>Se você precisa usar callbacks (especialmente em código existente), siga estas práticas:</p>

<p><strong>Use nomes descritivos</strong> para deixar claro que é um callback:</p>

<pre><code class="language-javascript">function processarDados(dados, quandoTerminar) {

setTimeout(function() {

const resultado = dados.map(x =&gt; x * 2);

quandoTerminar(resultado);

}, 500);

}

processarDados([1, 2, 3], function(resultado) {

console.log(resultado);

});</code></pre>

<p><strong>Sempre trate erros</strong> — nunca suponha que tudo correrá bem:</p>

<pre><code class="language-javascript">function operacaoRisca(callback) {

setTimeout(function() {

const sucesso = Math.random() &gt; 0.5;

if (sucesso) {

callback(null, &quot;Operação bem-sucedida&quot;);

} else {

callback(new Error(&quot;Falha na operação&quot;), null);

}

}, 1000);

}

operacaoRisca(function(erro, resultado) {

if (erro) {

console.error(&quot;Erro:&quot;, erro.message);

} else {

console.log(resultado);

}

});</code></pre>

<p><strong>Evite callbacks aninhados</strong> — separe em funções nomeadas:</p>

<pre><code class="language-javascript">function etapa1(callback) {

setTimeout(() =&gt; callback(null, &quot;Dados 1&quot;), 300);

}

function etapa2(dados1, callback) {

setTimeout(() =&gt; callback(null, dados1 + &quot; + Dados 2&quot;), 300);

}

function etapa3(dados2, callback) {

setTimeout(() =&gt; callback(null, dados2 + &quot; = Resultado Final&quot;), 300);

}

etapa1(function(erro, resultado1) {

if (erro) return console.error(erro);

etapa2(resultado1, function(erro, resultado2) {

if (erro) return console.error(erro);

etapa3(resultado2, function(erro, resultado3) {

if (erro) return console.error(erro);

console.log(resultado3);

});

});

});</code></pre>

<h2>Conclusão</h2>

<p>Callbacks são a base do assincronismo em JavaScript e ainda aparecem em muitas APIs nativas e bibliotecas. O padrão error-first callback é especialmente importante em Node.js. Embora Promises e async/await sejam superiores para novo código, dominar callbacks é essencial para compreender JavaScript profundamente e trabalhar com código legado com confiança. O principal aprendizado é que callbacks permitem executar código depois que uma operação termina, mas em cascatas complexas eles se tornam difíceis de manter — justamente por isso a linguagem evoluiu.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://developer.mozilla.org/pt-BR/docs/Glossary/Callback_function" target="_blank" rel="noopener noreferrer">MDN - Callbacks</a></li>

<li><a href="https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/" target="_blank" rel="noopener noreferrer">Node.js - Error-first Callbacks</a></li>

<li><a href="https://javascript.info/callbacks" target="_blank" rel="noopener noreferrer">JavaScript.info - Introduction to callbacks</a></li>

<li><a href="https://eloquentjavascript.net/11_async.html" target="_blank" rel="noopener noreferrer">Eloquent JavaScript - Asynchronous Programming</a></li>

<li><a href="https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/async-performance" target="_blank" rel="noopener noreferrer">You Don&#039;t Know JS - Async &amp; Performance</a></li>

</ul>

Comentários

Mais em JavaScript

Guia Completo de TypeScript com Node.js e Express: APIs Tipadas do Zero
Guia Completo de TypeScript com Node.js e Express: APIs Tipadas do Zero

Configuração Inicial do Ambiente Antes de iniciar qualquer projeto com TypeSc...

Guia Completo de Testes End-to-End em JavaScript com Playwright e Cypress
Guia Completo de Testes End-to-End em JavaScript com Playwright e Cypress

Introdução aos Testes End-to-End Testes end-to-end (E2E) verificam sua aplica...

Como Usar Classes em JavaScript: Sintaxe, Herança e Encapsulamento em Produção
Como Usar Classes em JavaScript: Sintaxe, Herança e Encapsulamento em Produção

Fundamentos de Classes em JavaScript Classes em JavaScript são açúcar sintáti...