Javascript – Entendendo Callback

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: http://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 (http://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 (http://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.

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: http://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 (http://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 (http://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:

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.

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.

Últimos posts por Ramos de Souza Janones (exibir todos)

Share this post

scroll to top