Javascript – Entendendo Callback

Javascript – Entendendo Callback

5 de agosto de 2018 0 Por Ramos de Souza Janones

Callback é uma função que é usada como “callback”. Ela é tipicamente passada como argumento de outra função e/ou chamada quando um evento for acontecido, ou quando uma parte de código receber uma resposta de que estava à espera.

Isto é muito comum em javascript lado cliente e servidor (NodeJS) mas não só. A função callback é muitas vezes assíncrona na medida em que é chamada como consequência de outro código que esta a correr no background. A grande vantagem é que assim o computador pode ir processando outros processos enquanto a resposta não chega e não precisa assim de parar tudo à espera dessa resposta.

Um exemplo clássico é um auscultador de eventos que chama uma função quando o evento acontece:

function callback(e) {
    alert('Aconteceu um evento ' + e.type);
}
window.addEventListener('click', callback);

Este callback vai ser chamada quando fizer um click na janela. Até isso acontecer o processador vai processando outras coisas que acontecem na aplicação.

Exemplo: https://jsfiddle.net/D2PuH/


Outro exemplo é uma chamada de ajax, que faz um pedido ao servidor e corre a função quando receber a resposta.

Essa função é uma função “callback”. No exemplo em baixo (https://jsfiddle.net/skQr7/) chamei-lhe minhaCallBack.

function minhaCallBack(returnhtml) {
    $("#result").html(returnhtml);
    $("#loadingimg").hide();
}

$(document).ready(function (e) {
        $.ajax({
            url: form_url,
            type: form_method,
            data: form_data,
            cache: false,
            success: minhaCallBack
        }); 
});

Outro exemplo ainda (https://jsfiddle.net/V3wDF/) é uma animação que chama a callback no fim da animação estar completa:

Vou fazer uma analogia entre código síncrono e código assíncrono.
Imaginando esta situação:

Problema:

Como transformar um numero no formato string, com parte decimal longa demais que deve ser convertido em dólares, e verificar se um dado cliente têm direito a desconto.

Solução síncrona:

Para resolver este problema de forma síncrona temos de saber o valor inicial e o valor do câmbio antes de iniciarmos o cálculo. Isto nem sempre é assim, mas para o exemplo vamos assumir que sabemos o seguinte:

var valorInicial = "1003,087293487";
var descontoCliente = "5%";
var cambio =  1.1158; // 1 EUR = 1.11580USD

assim podemos fazer a transformação de maneira simples:

var valorInicialEmFormatoNumerico = Number(valorInicial.replace(',', '.'));
var valorComDescontoAplicado = valorInicialEmFormatoNumerico - (valorInicialEmFormatoNumerico * parseFloat(descontoCliente) / 100);
var valorEmDolares = valorComDescontoAplicado * cambio;
var totalComDuasCasasDecimais = valorEmDolares.toFixed(2);

Assim o resultado é obtido com passos síncronos, e dá 1063.28

Solução assíncrona:

Imagina agora que precisamos de fazer a mesma coisa, mas não temos a informação toda disponível, pois os câmbios mudam constantemente, não podemos ter disponível o desconto de todos os possíveis clientes, e nem mesmo o preço inicial pois temos de perguntar ao nosso fornecedor primeiro.

Como fazer?

Neste caso temos de fazer a coisa assíncrona, ou seja correndo parte do código, esperar por respostas, correr mais um pedaço e esperar por outra resposta, etc…

Podemos dizer que quando perguntamos algo a um serviço exterior fazemos provavelmente um pedido ajax. E agora precisamos de uma ferramenta para receber a resposta, é aí que callbacks entram em jogo.

LEIA TAMBÉM:  React Native Do Zero Ao Profissional, Curso Sobre Criação De Apps React Native Para Android e IOS

Quando envio uma pergunta para um serviço externo tenho de lhe dizer como ele me deve contactar/informar com o resultado. Uma maneira comum é enviar uma função com o pedido para que ela seja corrida quando a resposta chegar.

enviar uma função com o pedido para que ela seja corrida quando a resposta chegar

Se eu enviar uma função a um setTimeout, digo ao setTimeout qual o código a correr quando o tempo tiver esgotado. Essa função pode ter o nome que quisermos, mas a sua funcionalidade, o seu tipo é callback:

var fazerAlgo = function(){ alert('O tempo chegou ao fim!'); }
setTimeout(fazerAlgo, 2000); // correr ao fim de 2 segundos

Voltando ao exemplo das contas:

Para fazermos o cálculo anterior com lógica assíncrona temos de encadear as coisas e depender de funções que vão sendo chamadas com tempos de espera entre elas. Assim temos de encadear tudo, por exemplo assim:

pedirPrecoAoFornecedor(numeroProduto, function(respostaDoFornecedor) {
  var valorInicialEmFormatoNumerico = Number(respostaDoFornecedor.replace(',', '.'));
  pedirInformacaoDesconto(numeroCliente, function(descontoCliente) {
    var valorComDescontoAplicado = valorInicialEmFormatoNumerico - (valorInicialEmFormatoNumerico * parseFloat(descontoCliente) / 100);
    pedirCambioDaHora('USD', function(valorDoDolar) {
      var valorEmDolares = valorComDescontoAplicado * valorDoDolar;
      var totalComDuasCasasDecimais = valorEmDolares.toFixed(2);

      // !! agora temos o resultado!! 
      alert(totalComDuasCasasDecimais + 'USD');

    })
  })
})

Callback é uma função que é usada como “callback”. Ela é tipicamente passada como argumento de outra função e/ou chamada quando um evento for acontecido, ou quando uma parte de código receber uma resposta de que estava à espera.

Isto é muito comum em javascript lado cliente e servidor (NodeJS) mas não só. A função callback é muitas vezes assíncrona na medida em que é chamada como consequência de outro código que esta a correr no background. A grande vantagem é que assim o computador pode ir processando outros processos enquanto a resposta não chega e não precisa assim de parar tudo à espera dessa resposta.

Um exemplo clássico é um auscultador de eventos que chama uma função quando o evento acontece:

function callback(e) {
    alert('Aconteceu um evento ' + e.type);
}
window.addEventListener('click', callback);

Este callback vai ser chamada quando fizer um click na janela. Até isso acontecer o processador vai processando outras coisas que acontecem na aplicação.

Exemplo: https://jsfiddle.net/D2PuH/


Outro exemplo é uma chamada de ajax, que faz um pedido ao servidor e corre a função quando receber a resposta.

Essa função é uma função “callback”. No exemplo em baixo (https://jsfiddle.net/skQr7/) chamei-lhe minhaCallBack.

function minhaCallBack(returnhtml) {
    $("#result").html(returnhtml);
    $("#loadingimg").hide();
}

$(document).ready(function (e) {
        $.ajax({
            url: form_url,
            type: form_method,
            data: form_data,
            cache: false,
            success: minhaCallBack
        }); 
});

Outro exemplo ainda (https://jsfiddle.net/V3wDF/) é uma animação que chama a callback no fim da animação estar completa:

function completa() {
    alert('Este alert está dentro da função "callback"');
}
$('div').animate({
    'height': '200px'
}, {
    duration: 2000,
    complete: completa
});

Outro exemplo ainda, para tentar clarificar mais depois de surgir mais uma pergunta sobre o assunto.

Vou fazer uma analogia entre código síncrono e código assíncrono.
Imaginando esta situação:

LEIA TAMBÉM:  Mas, afinal, como é gerada a randomização pelo computador?

Problema:

Como transformar um numero no formato string, com parte decimal longa demais que deve ser convertido em dólares, e verificar se um dado cliente têm direito a desconto.

Solução síncrona:

Para resolver este problema de forma síncrona temos de saber o valor inicial e o valor do câmbio antes de iniciarmos o cálculo. Isto nem sempre é assim, mas para o exemplo vamos assumir que sabemos o seguinte:

var valorInicial = "1003,087293487";
var descontoCliente = "5%";
var cambio =  1.1158; // 1 EUR = 1.11580USD

assim podemos fazer a transformação de maneira simples:

var valorInicialEmFormatoNumerico = Number(valorInicial.replace(',', '.'));
var valorComDescontoAplicado = valorInicialEmFormatoNumerico - (valorInicialEmFormatoNumerico * parseFloat(descontoCliente) / 100);
var valorEmDolares = valorComDescontoAplicado * cambio;
var totalComDuasCasasDecimais = valorEmDolares.toFixed(2);

Assim o resultado é obtido com passos síncronos, e dá 1063.28

Solução assíncrona:

Imagina agora que precisamos de fazer a mesma coisa, mas não temos a informação toda disponível, pois os câmbios mudam constantemente, não podemos ter disponível o desconto de todos os possíveis clientes, e nem mesmo o preço inicial pois temos de perguntar ao nosso fornecedor primeiro.

Como fazer?

Neste caso temos de fazer a coisa assíncrona, ou seja correndo parte do código, esperar por respostas, correr mais um pedaço e esperar por outra resposta, etc…

Podemos dizer que quando perguntamos algo a um serviço exterior fazemos provavelmente um pedido ajax. E agora precisamos de uma ferramenta para receber a resposta, é aí que callbacks entram em jogo.

Quando envio uma pergunta para um serviço externo tenho de lhe dizer como ele me deve contactar/informar com o resultado. Uma maneira comum é enviar uma função com o pedido para que ela seja corrida quando a resposta chegar.

enviar uma função com o pedido para que ela seja corrida quando a resposta chegar

Se eu enviar uma função a um setTimeout, digo ao setTimeout qual o código a correr quando o tempo tiver esgotado. Essa função pode ter o nome que quisermos, mas a sua funcionalidade, o seu tipo é callback:

var fazerAlgo = function(){ alert('O tempo chegou ao fim!'); }
setTimeout(fazerAlgo, 2000); // correr ao fim de 2 segundos

Voltando ao exemplo das contas:

para fazermos o cálculo anterior com lógica assíncrona temos de encadear as coisas e depender de funções que vão sendo chamadas com tempos de espera entre elas. Assim temos de encadear tudo, por exemplo assim:

pedirPrecoAoFornecedor(numeroProduto, function(respostaDoFornecedor) {
  var valorInicialEmFormatoNumerico = Number(respostaDoFornecedor.replace(',', '.'));
  pedirInformacaoDesconto(numeroCliente, function(descontoCliente) {
    var valorComDescontoAplicado = valorInicialEmFormatoNumerico - (valorInicialEmFormatoNumerico * parseFloat(descontoCliente) / 100);
    pedirCambioDaHora('USD', function(valorDoDolar) {
      var valorEmDolares = valorComDescontoAplicado * valorDoDolar;
      var totalComDuasCasasDecimais = valorEmDolares.toFixed(2);

      // !! agora temos o resultado!! 
      alert(totalComDuasCasasDecimais + 'USD');

    })
  })
})

Este encadeamento de funções é necessário pois cada callback será chamada quando o serviço externo quiser. Por exemplo a função pedirPrecoAoFornecedor recebe dois argumentos: o numero do produto e uma função. Como eu sei que o que vou receber é o preço do produto coloco já isso como nome da variável, para facilitar a leitura. Essa função que passo a pedirPrecoAoFornecedor é portanto uma callback, um mecanismo para o serviço externo me poder devolver o que preciso.

LEIA TAMBÉM:  React - O que é Shadow DOM

Ramos de Souza Janones

Janones, é um empreendedor brasileiro apaixonado por empreendedorismo e tecnologia. Ao longo dos anos trabalhando com o desenvolvimento de softwares desktop desde a linguagem Clipper, passando pelo Delphi e atualmente com Java.

Optou pela formação de Publicidade e Marketing por sua segunda empresa de tecnologia ter participado do "boom" da internet nos anos 90 e na procura de melhorar seus conhecimentos em negócios.

Em razão da principal formação e profundos conhecimentos em programação e banco de dados, é capaz de realizar o desenvolvimento de aplicativos web, desktop e mobile com maior criatividade e inovação que profissionais de desenvolvimento com uma formação única e mais especifica, dedicada somente ao desenvolvimento de softwares.

Com toda sua experiência com empresas de software, sua formação e paixão por negócios escreveu o livro "Marketing para Empresas e Profissionais de Software", publicado pela editora carioca Ciência Moderna em 2012. Além de outros livros sobre programação.