Qual é a diferença entre uma função de retorno de chamada e um ouvinte de evento?

Uma função de retorno de chamada é uma função, em JavaScript. É passado para outra função como argumento, que é invocado dentro da função externa para concluir algum tipo de rotina ou ação.

Um ouvinte de evento também é uma função de retorno de chamada, um tipo especial (veja detalhes na parte inferior).

Exemplo de função de retorno de chamada:

saudação de função (msg) {
    console.log (msg);
}
função sayHello (nome, retorno de chamada) {
    const greet = 'Olá' + nome;
    retorno de chamada (cumprimentar);
}
sayOlá ('João', saudação);
Olá john

A função de retorno de chamada também pode ser transmitida como uma função anônima ou seta:

sayHello ('John', função (texto) {console.log (texto)});
sayHello ('John', (texto) => console.log (texto));

O exemplo acima é um retorno de chamada síncrono, pois é executado imediatamente.

Um retorno de chamada assíncrono:

const getData = função (retorno de chamada) {
    const data = {note: 'A mensagem é: Tic-tac-toe'};
    setTimeout (() => {
        retorno de chamada (dados);
    } 3000)
}
retorno de chamada const = função (dados) {
    console.log (data.note)
}
getData (retorno de chamada);
A mensagem é: Tic-tac-toe

A função getData recebe um retorno de chamada que é executado após algum trabalho (nesse caso, o trabalho retorna após 3 segundos com um objeto).

Ouvintes de Eventos no Navegador:

Vamos pegar este exemplo de código usando HTML e JS:

O HTML:


  
      
      
 

Sempre que o elemento do botão é clicado, um pop-up com o botão "Login clicado!" vai aparecer. A ação de clique no botão produz um evento 'clique'. Por sua vez, executa a função de manipulador de clique que lida com o evento click - executa algum código em uma função. A função do manipulador é uma função de retorno de chamada.

Observe que esta função é um retorno de chamada. Além disso, a função é executada quando um evento específico ocorre. Este é um ouvinte de eventos.

Ouvintes de Eventos no NodeJS:

O módulo de eventos possui uma classe EventEmitter com recursos usando esse conceito de ouvinte de evento. Aqui está um exemplo:

const EventEmitter = require ('eventos');
emissor constante = novo EventEmitter ();
emitter.addListener ('ev', function () {
    console.log ('ocorreu um evento!');
});
emitter.emit ('ev');
um evento ocorreu!

No código acima, a função anônima transmitida ao método addListener do emissor é um ouvinte de eventos e também uma função de retorno de chamada. O retorno de chamada é executado sempre que um evento 'ev' é emitido pelo emissor (usando o método de emissão).

A diferença é que uma função de retorno de chamada, como o nome diz, é uma função usada como retorno de chamada.

Como exemplo:

função connect ($ address, $ callback) {
   $ conectado = conectar0 (endereço $);

   if ($ conectado) {
      $ callback-> execute ();
   }
}

connect ("123.123.123.123:8080", function () {
   eco "Conectado com sucesso!";
});

De um modo geral, a função de retorno de chamada é algo que você passa no tempo de design (quando você escreve seu programa), e geralmente é um argumento e, em muitos casos, necessário. E, é claro, na maioria das vezes o retorno de chamada é implementado como uma função, não como classe.

Em outras palavras, um retorno de chamada é algo esperado pelo código do aplicativo ou módulo e será (na maioria dos casos) sempre executado.

O Event Listener é uma classe ou uma função que é chamada em tempo de execução (momento em que seu programa é realmente executado). Normalmente faz parte de um conceito maior chamado padrão Observador (ou Publicador / Assinante), em que alguns componentes de aplicativos se inscrevem em eventos e outros componentes emitem esses eventos (sem saber ou se importar com quem está inscrito). Daí outra diferença: um evento, quando despachado, pode ser tratado por nenhum, um ou vários ouvintes, e o módulo que o emite pode nem saber ou se importar com os ouvintes conectados.

Por outro lado, o módulo sempre sabe qual retorno de chamada espera e quando executá-lo. Essa lógica é codificada no módulo.

Conseqüentemente, os Listeners de Eventos permitem criar aplicativos muito mais frouxamente acoplados (o que é bom). Por outro lado, quando você está visualizando o código que emite o evento, geralmente é difícil dizer quais ouvintes serão chamados, sem inspecionar outras partes do código.

Considere um exemplo em Javascript:

// Uma implementação básica do Event Observer

deixe ouvintes = {}

função listen (evento, newListener) {
// descartar ouvintes inválidos
if ('function'! == typeof newListener) {
Retorna
    }

// configure um novo evento, se necessário
    if ('indefinido' === tipo de ouvintes [evento]) {
        listeners [evento] = nova matriz
    }
    
    // registra o ouvinte no evento
    listeners [event] .push (newListener)
}

função emitir (evento, dados) {
if (Array.isArray (listeners [evento])) {
        listeners [event] .forEach (ouvinte => ouvinte (dados))
    }
}

função assíncrona fetchApiData (terminal, retorno de chamada) {
deixe request = new XMLHttpRequest ()
    request.open ('GET', ponto final)
    resposta constante = aguardar request.send ()

    if ('function' === typeof callback) {
    retorno de chamada (resposta)
    }

    emit ('api_response', resposta)
}

Imagine que o código acima esteja empacotado como um módulo de terceiros e você o importe e use em seu aplicativo.

"FetchApiData" aceita um retorno de chamada e emite eventos. Isso permite que você o use de 2 maneiras diferentes.

Agora, se você deseja executar essa lógica de sucesso apenas em uma situação específica, transmite um retorno de chamada:

fetchApiData (
'https://myawesomeapi.io',
    response => console.log ('Hooray! resposta recebida! Mas psssst!')
)

Mas se existe alguma lógica que você sabe que sempre será executada para todo tipo de resposta, você pode registrar um ouvinte de evento e esquecer a necessidade de qualquer retorno de chamada:

listen ('api_response', response => silentlyLogResponse (response))

agora sempre que você chamar fetchApiData, ele chamará silentlyLogResponse (response) porque emite o evento automaticamente. Não há mais necessidade de retornar o retorno de chamada.

fetchApiData ('https://myawesomeapi.io') // chama silenciosamenteLogResponse

e você pode registrar quantos ouvintes quiser em um evento:

listen ('api_response', updateDOM)
listen ('api_response', makeCoffee)
listen ('api_response', playMusic)
listen ('api_response', makeAmericaGreatAgain)

E todos serão executados sempre que um evento for emitido.

Pergunta: Qual é a diferença entre uma função de retorno de chamada e um ouvinte de evento?

A diferença é principalmente apenas caso de uso. Eles são essencialmente a mesma coisa exata. Cada uma é uma função ou procedimento executado após a conclusão de algum evento ou atividade.

Por exemplo, em C, existe uma função chamada qsort () que executa uma classificação rápida em uma matriz ou buffer e exige que ele passe um ponteiro para uma função - uma função de retorno de chamada. Essa função para todos os propósitos e finalidades pode ser considerada um manipulador de eventos onCompare (), pois essa função / ponteiro é chamada sempre que 2 itens no conjunto passados ​​a ele precisarem ser comparados entre si.

Essencialmente, funções de retorno de chamada, manipuladores de eventos, ouvintes, publicador / assinante e Observable / Observer são nomes diferentes para o mesmo padrão de design com casos de uso ligeiramente diferentes. As funções de retorno de chamada geralmente são chamadas como tal quando alguém chama uma função e precisa passar a função de retorno de chamada para a primeira função que está sendo chamada. Geralmente é também por um período muito curto. Na situação em que um campo em uma classe / objeto está sendo definido, frequentemente isso é chamado de manipulador de eventos. No entanto, existem muitas situações, especialmente em Javascript no JQuery, em que se chama funções / métodos como setClick () e passa uma função como argumento. Isso ocorre por um período muito maior do que a execução de uma função. O mesmo acontece com Publicador / Assinante e Observável / Observador - Períodos mais longos. Ouvintes são essencialmente a mesma coisa que Manipuladores de Eventos, mas o termo é preferido em algumas linguagens como Java.