W3docs

Callbacks em JavaScript

Em JavaScript, callbacks são um conceito essencial que permite aos desenvolvedores lidar com operações assíncronas de forma eficaz.

Um callback é simplesmente uma função que você passa para outra função como argumento, para que a função receptora possa chamá-la de volta mais tarde. Como funções são valores de primeira classe em JavaScript — podem ser armazenadas em variáveis, passadas adiante e retornadas — qualquer função pode aceitar outra função como parâmetro. Essa única ideia alimenta tudo, desde métodos de array como map até temporizadores e requisições de rede.

Este capítulo aborda o que são callbacks, a diferença entre callbacks síncronos e assíncronos, a convenção error-first, o problema do callback hell que eles criam e como Promises e async/await o resolvem.

Um Primeiro Callback

A função que você passa é o callback; a função que a recebe e invoca é a função de ordem superior. Aqui, um callback é executado após a conclusão de algum trabalho:

javascript— editable

finishTask é passado para completeTask e invocado dentro dela. Note que você passa o nome da função (finishTask) sem parênteses — adicionar () a chamaria imediatamente e passaria seu valor de retorno em vez disso.

Callbacks Síncronos vs. Assíncronos

Nem todo callback é sobre espera. Existem dois tipos distintos, e confundi-los é uma fonte comum de bugs.

Callbacks síncronos

Um callback síncrono é executado imediatamente, em ordem, antes que a função externa retorne. Métodos de array são o exemplo clássico:

javascript— editable

Aqui, transform é chamado e concluído para cada elemento antes de map retornar. Métodos embutidos como Array.prototype.map, filter, forEach e sort aceitam callbacks síncronos.

Callbacks assíncronos

Um callback assíncrono é entregue a uma operação que será concluída mais tarde — um temporizador, leitura de arquivo ou requisição de rede. A função externa retorna imediatamente, e o callback é disparado assim que o resultado estiver pronto. JavaScript agenda esses callbacks por meio do event loop, que os enfileira e executa quando a pilha de chamadas está vazia.

javascript— editable

Mesmo com um atraso de 0ms, o callback é executado depois do código síncrono ao redor. Essa é a característica definidora de um callback assíncrono: ele não pode retornar um valor da maneira normal, portanto a única forma de usar o resultado é colocar seu código de continuação dentro do callback. Para entender exatamente quando eles são executados, veja JavaScript: Event Loop.

A Convenção Error-First

Callbacks assíncronos não podem usar throw para o código que iniciou a operação — quando são executados, aquele código já retornou há muito tempo. A comunidade estabeleceu uma convenção: passar o erro como o primeiro argumento e o resultado como o segundo. O callback sempre verifica o erro primeiro.

javascript— editable

Quando tudo ocorre com sucesso, o campo de erro é null. Essa assinatura (err, result) é o padrão nas APIs do Node.js (fs.readFile, dns.lookup e muitos outros).

Callback Hell: A Pirâmide da Perdição

Callbacks funcionam bem para uma única operação. O problema começa quando uma etapa assíncrona depende do resultado da anterior. Cada etapa se aninha dentro da última, e o recuo avança para a direita — a chamada pirâmide da perdição:

javascript— editable

Com duas etapas ainda é legível. Adicione uma terceira e quarta — e repita a verificação if (err) em cada camada — e o código se torna difícil de acompanhar, difícil de tratar erros e difícil de alterar. Isso é o callback hell, e é a principal razão pela qual as Promises foram introduzidas.

Boas Práticas para Usar Callbacks

Embora os callbacks sejam poderosos, usá-los excessivamente ou de forma incorreta pode levar ao "callback hell", onde o código fica muito aninhado e difícil de ler e manter. Aqui estão algumas boas práticas para manter seu código limpo:

  1. Modularize Seu Código: Divida suas funções de callback em funções menores e reutilizáveis. Essa abordagem não só melhora a legibilidade, como também facilita a manutenção do código.
  2. Trate Erros com Elegância: Sempre trate erros em seus callbacks. Essa prática evita falhas e comportamentos indesejados em ambientes de produção.
  3. Evite Aninhamento Profundo: Tente achatar suas estruturas de callback ao máximo possível. Ferramentas como async/await ou Promises podem ajudar a gerenciar operações assíncronas de forma mais limpa.
  4. Cuidado com Closures em Laços: Ao definir callbacks dentro de laços, use let ou const para variáveis do laço a fim de evitar bugs relacionados a closures, onde todos os callbacks capturam o valor final do laço.

Indo Além dos Callbacks: Promises e Async/Await

Embora callbacks sejam uma parte fundamental do JavaScript, o JavaScript moderno oferece formas mais abstratas de lidar com código assíncrono, como Promises e async/await.

Usando Promises

Uma Promise representa um valor que pode estar disponível agora, no futuro ou nunca. Em vez de aninhar, etapas dependentes são encadeadas uma após a outra, o que achata a pirâmide e centraliza o tratamento de erros em um único .catch. Comece com JavaScript: Promises, depois veja como as etapas se conectam em JavaScript: Encadeamento de Promises.

Se você tiver uma função antiga baseada em callback (como os exemplos de divide ou getUser acima), pode envolvê-la para que retorne uma Promise — uma técnica chamada promisificação. Veja JavaScript: Promisificação.

Async/Await: Uma Abordagem Mais Limpa

A sintaxe async/await permite escrever código assíncrono que parece código síncrono. É construída sobre Promises e é mais intuitiva do que os padrões tradicionais de callback. Leia JavaScript: Async/Await para ver como você pode usar async/await em vez de callbacks.

Conclusão

Compreender e utilizar callbacks de forma eficaz é crucial para desenvolvedores JavaScript. Seguindo boas práticas e usando recursos modernos como Promises e async/await, você pode escrever código mais limpo e de fácil manutenção. Domine esses conceitos para aprimorar suas habilidades de programação em JavaScript e construir aplicações mais eficientes.

Prática

Prática
O que é uma função callback em JavaScript e quando ela é executada?
O que é uma função callback em JavaScript e quando ela é executada?
Was this page helpful?