O que são Callbacks?

Introdução

Opa galera, tudo tranquilo?

Quem acompanha a Coday com certeza viu, ou verá, muitos posts nesse estilo mais teórico. Vamos bater repetidamente na tecla de que esse tipo de conhecimento é fundamental para qualquer desenvolvedor, principalmente para aqueles que buscam ingressar no mercado de trabalho. Muitos dos concorrentes a uma vaga deixam a desejar em conhecimentos mais básicos na hora da entrevista técnica, e um desses conhecimentos pode estar relacionado com o assunto deste post: as callbacks.

Callbacks

Os computadores são assíncronos por design.

Isso significa que as coisas podem acontecer independentemente do fluxo do programa principal.

Nos computadores atuais, cada programa é executado por um intervalo de tempo específico e, em seguida, interrompe sua execução para permitir que outro programa seja executado. Esse ciclo acontece tão rápido que é impossível perceber, assim acabamos pensando que nossos computadores executam diversos programas simultaneamente, mas isso é uma ilusão (exceto em máquinas com multiprocessadores).

Os programas usam, internamente, as interrupções, um sinal emitido para o processador para ganhar a atenção do sistema.

Não vvamos focar nisso, mas lembre-se de que é normal que os programas sejam assíncronos e interrompam sua execução até que precisem de atenção, e o computador pode executar outras coisas nesse meio tempo. Quando um programa está aguardando uma resposta da rede, ele não pode parar o processador até que a solicitação seja concluída.

Normalmente, as linguagens de programação são síncronas e algumas fornecem uma maneira de gerenciar a assincronicidade, seja na linguagem ou através de bibliotecas. C, Java, C #, PHP, Go, Ruby, Swift, Python, são todas síncronas por padrão. Algumas delas lidam com async usando threads, gerando um novo processo.

O JavaScript é síncrono por padrão e single threaded. Isso significa que o código não pode criar novos threads e executar em paralelo.

As linhas de código são executadas em série, uma após a outra, por exemplo:

const a = 1
const b = 2
const c = a * b
console.log(c)
doSomething()

Mas o JavaScript nasceu dentro do navegador, e sua principal tarefa, no início, era responder a ações do usuário, como onClick, onMouseOver, onChange, onSubmit e assim por diante. Como isso poderia ser feito com um modelo de programação síncrona?

A resposta estava em seu ambiente. O navegador fornece uma maneira de fazer isso, fornecendo um conjunto de APIs que podem lidar com esse tipo de funcionalidade.

Mais recentemente, o Node.js introduziu um ambiente de E / S sem bloqueio para estender esse conceito ao acesso a arquivos, chamadas de rede e assim por diante.

Você não sabe quando um usuário clicará em um botão; portanto, o que você faz é definir um manipulador de eventos para o evento de clique. Este manipulador de eventos aceita uma função, que será chamada quando o evento for disparado:

document.getElementById("button").addEventListener("click", () => {
  // item clicado
})

Esta é uma callback.

Uma callback é uma função simples que é passada como um valor para outra função e só será executada quando o evento acontecer. Podemos fazer isso porque o JavaScript possui funções de primeira classe, que podem ser atribuídas a variáveis e transmitidas para outras funções (chamadas funções de ordem superior)

É comum agrupar todo o seu código de cliente em um eventListener de carregamento no windowobject, que executa a callback somente quando a página estiver pronta:

window.addEventListener("load", () => {
  // janela carregada
  //faça o que você quiser
})

Callbacks são usadas em todo o lugar, não apenas em eventos da DOM.

Um exemplo comum é usando os temporizadores:

setTimeout(() => {
  // runs after 2 seconds
}, 2000)

Tratando erros nas callbacks

Como você lida com erros nas callbacks? Uma estratégia muito comum é usar o que o Node.js adotou: o primeiro parâmetro em qualquer callback é o objeto de erro.

Se não houver erro, o objeto é null. Se houver um erro, ele conterá uma descrição do erro e outras informações

fs.readFile("/file.json", (err, data) => {
  if (err !== null) {
    //handle error
    console.log(err)
    return
  }

  //no errors, process data
  console.log(data)
})

O problema com as callbacks

Callbacks são ótimas para casos simples, no entanto, toda callback adiciona um nível de aninhamento e, quando você tem muitas callbacks, o código começa a se complicar muito rapidamente:

window.addEventListener("load", () => {
  document.getElementById("button").addEventListener("click", () => {
    setTimeout(() => {
      items.forEach(item => {
        //your code here
      })
    }, 2000)
  })
})

Este é apenas um código simples de quatro níveis, mas pode haver muito mais aninhamento.

Como podemos solucionar isso?

Alternativas a Callbacks

A partir do ES6, o JavaScript introduziu vários recursos que nos ajudam com código assíncrono que não envolve o uso de callbacks:

Promises (ES6) Async/Await (ES8)

Conclusão

Por hoje é isso galera, espero que tenham curtido o assunto e que este post possa ter lhes agregado conhecimeto.

Se vocês tiverem quaisquer dúvidas relacionadas ao tema, ou quiserem sugerir algum outro tema, deixem aqui nos comentários.

Comentários