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.
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)
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)
})
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)
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.