O que é uma função de retorno de chamada?


684

O que é uma função de retorno de chamada?


8
você pode encontrar aqui: stackoverflow.com/a/9652434/3343174 a melhor explicação sobre retornos de chamada
Fakher


Olhada segunda resposta para o detalhe explicação
Donato

A melhor explicação de retorno de chamada que eu já encontrado youtube.com/watch?v=xHneyv38Jro
Sameer Sinha

Respostas:


680

Os desenvolvedores geralmente ficam confusos com o que é um retorno de chamada por causa do nome da coisa amaldiçoada.

Uma função de retorno de chamada é uma função que é:

  • acessível por outra função e
  • é invocado após a primeira função se essa primeira função for concluída

Uma boa maneira de imaginar como funciona uma função de retorno de chamada é que ela é " chamada na parte de trás" " da função para a qual é passada.

Talvez um nome melhor seria um "ligar depois" .

Essa construção é muito útil para comportamento assíncrono, onde queremos que uma atividade ocorra sempre que um evento anterior for concluído.

Pseudo-código:

// A function which accepts another function as an argument
// (and will automatically invoke that function when it completes - note that there is no explicit call to callbackFunction)
funct printANumber(int number, funct callbackFunction) {
    printout("The number you provided is: " + number);
}

// a function which we will use in a driver function as a callback function
funct printFinishMessage() {
    printout("I have finished printing numbers.");
}

// Driver method
funct event() {
   printANumber(6, printFinishMessage);
}

Resultado se você chamou event ():

The number you provided is: 6
I have finished printing numbers.

A ordem da saída aqui é importante. Como as funções de retorno de chamada são chamadas posteriormente, "Eu terminei de imprimir números" é impresso por último, não primeiro.

Os retornos de chamada são chamados devido ao uso nos idiomas dos ponteiros. Se você não usar um desses, não trabalhe com o nome 'callback'. Entenda que é apenas um nome para descrever um método que é fornecido como argumento para outro método, de modo que, quando o método pai é chamado (qualquer condição, como um clique no botão, um tique de timer etc.) e seu corpo é concluído, a função de retorno de chamada é então invocada.

Alguns idiomas suportam construções nas quais vários argumentos da função de retorno de chamada são suportados e são chamados com base em como a função pai é concluída (ou seja, um retorno de chamada é chamado no caso em que a função pai é concluída com êxito, outro é chamado no caso em que a função pai lança um erro específico, etc).


31
Seu exemplo é ótimo, mas não vejo por que a terminologia é "retorno de chamada". Quando o meaningOfLife é "chamado de volta"?
CodyBugstein

4
Olá, sobre once its parent method completes, the function which this argument represents is then called. Então, se a função é passada para outra função como argumento, mas é chamada a partir do meio do tempo de execução da função pai parent(cb) {dostuff1(); cb(); dostuff2()}, ela não é considerada uma callbackfunção?
Max Yari

2
@MaxYari: IMHO, ainda é considerado como retorno de chamada. O importante aqui é que a função pai usará a função de entrada (também conhecida como retorno de chamada) de alguma forma. Pode ser chamado no meio ou no final ou se uma condição for atendida.
Kamran Bigdely

12
@ 8bitjunkie obrigado - mas onde o método meaningOfLife é chamado na função printANumber?
BKSpurgeon

2
Isso não é verdade: "é automaticamente chamado após a conclusão da primeira função". Um retorno de chamada não precisa ser executado, muito menos automaticamente. De fato, não é incomum que os retornos de chamada sejam concluídos antes que a função pai seja concluída. Não gosto muito de como as pessoas descrevem os retornos de chamada como sendo funções executadas "mais tarde". É muito confuso para as pessoas que estão aprendendo sobre eles. Simplificando, retornos de chamada são apenas funções que são passadas como argumentos para outras funções. Período. Uma explicação melhor incluiria a explicação de por que retornos de chamada sobre referências de função.
Jordan

224

Definição Opaca

Uma função de retorno de chamada é uma função que você fornece a outro trecho de código, permitindo que ela seja chamada por esse código.

Exemplo artificial

Por que você quer fazer isso? Digamos que exista um serviço que você precise chamar. Se o serviço retornar imediatamente, você apenas:

  1. Chame-o
  2. Aguarde o resultado
  3. Continue assim que o resultado chegar

Por exemplo, suponha que o serviço fosse a factorialfunção. Quando você deseja o valor de 5!, invoca factorial(5)e as seguintes etapas ocorrem:

  1. Seu local de execução atual é salvo (na pilha, mas isso não é importante)

  2. A execução é entregue a factorial

  3. Quando factorialconcluído, coloca o resultado em algum lugar que você pode chegar a ele

  4. A execução volta para onde estava [1]

Agora, suponha que factorialdemorou muito tempo, porque você está dando números enormes e ele precisa ser executado em algum cluster de supercomputação em algum lugar. Digamos que você espere 5 minutos para retornar seu resultado. Você poderia:

  1. Mantenha seu design e execute seu programa à noite quando estiver dormindo, para não ficar olhando a tela metade do tempo

  2. Crie seu programa para fazer outras coisas enquanto factorialestiver fazendo

Se você escolher a segunda opção, os retornos de chamada poderão funcionar para você.

Design de ponta a ponta

Para explorar um padrão de retorno de chamada, o que você deseja é poder chamar factorialda seguinte maneira:

factorial(really_big_number, what_to_do_with_the_result)

O segundo parâmetro,, what_to_do_with_the_resulté uma função para a qual você envia factorial, na esperança de factorialchamá-lo em seu resultado antes de retornar.

Sim, isso significa que factorial precisa ter sido escrito para oferecer suporte a retornos de chamada.

Agora, suponha que você queira passar um parâmetro para seu retorno de chamada. Agora você não pode, porque não vai chamá-lo, factorialé. Portanto, ele factorialprecisa ser gravado para permitir que você transmita seus parâmetros e os entregará ao retorno de chamada quando o chamar. Pode ser assim:

factorial (number, callback, params)
{
    result = number!   // i can make up operators in my pseudocode
    callback (result, params)
}

Agora que factorialpermite esse padrão, seu retorno de chamada pode ser assim:

logIt (number, logger)
{
    logger.log(number)
}

e sua chamada para factorialseria

factorial(42, logIt, logger)

E se você quiser devolver algo logIt? Bem, você não pode, porquefactorial não está prestando atenção a isso.

Bem, por que não factorial basta retornar o que seu retorno de chamada retorna?

Tornando-o sem bloqueio

Como a execução deve ser entregue ao retorno de chamada quando factorialterminar, ela realmente não deve retornar nada ao chamador. E, idealmente, de alguma forma, lançaria seu trabalho em outro encadeamento / processo / máquina e retornaria imediatamente para que você pudesse continuar, talvez algo como isto:

factorial(param_1, param_2, ...)
{
    new factorial_worker_task(param_1, param_2, ...);
    return;
}

Agora, essa é uma "chamada assíncrona", o que significa que, quando você a chama, ela retorna imediatamente, mas ainda não fez seu trabalho. Portanto, você precisa de mecanismos para verificá-lo e obter seu resultado quando terminar, e seu programa ficou mais complexo no processo.

A propósito, usando esse padrão, você factorial_worker_taskpode iniciar seu retorno de chamada de forma assíncrona e retornar imediatamente.

Então, o que você faz?

A resposta é permanecer dentro do padrão de retorno de chamada. Sempre que você quiser escrever

a = f()
g(a)

e fdeve ser chamado de forma assíncrona, você escreverá

f(g)

onde gé passado como retorno de chamada.

Isso muda fundamentalmente a topologia de fluxo do seu programa e leva algum tempo para se acostumar.

Sua linguagem de programação pode ajudá-lo muito, oferecendo uma maneira de criar funções on-the-fly. No código imediatamente acima, a função gpode ser tão pequena quantoprint (2*a+1) . Se o seu idioma exigir que você defina isso como uma função separada, com um nome e uma assinatura totalmente desnecessários, sua vida ficará desagradável se você usar muito esse padrão.

Se, por outro lado, a sua linguagem permite criar lambdas, você está em uma forma muito melhor. Você acabará escrevendo algo como

f( func(a) { print(2*a+1); })

o que é muito melhor.

Como passar o retorno de chamada

Como você passaria a função de retorno de chamada factorial? Bem, você poderia fazer isso de várias maneiras.

  1. Se a função chamada estiver sendo executada no mesmo processo, você poderá passar um ponteiro de função

  2. Ou talvez você queira manter um dicionário fn name --> fn ptrno seu programa, caso em que você pode passar o nome

  3. Talvez seu idioma permita que você defina a função no local, possível como um lambda! Internamente, ele cria algum tipo de objeto e passa um ponteiro, mas você não precisa se preocupar com isso.

  4. Talvez a função que você está chamando esteja sendo executada em uma máquina totalmente separada e você esteja chamando-a usando um protocolo de rede como HTTP. Você pode expor seu retorno de chamada como uma função que pode ser chamada por HTTP e passar seu URL.

Você entendeu a ideia.

O recente aumento de retornos de chamada

Nesta era da web em que entramos, os serviços que chamamos geralmente estão na rede. Geralmente, não temos controle sobre esses serviços, ou seja, não os escrevemos, não os mantemos, não podemos garantir que eles estejam funcionando ou que estejam funcionando.

Mas não podemos esperar que nossos programas sejam bloqueados enquanto aguardamos a resposta desses serviços. Consciente disso, os provedores de serviços geralmente projetam APIs usando o padrão de retorno de chamada.

O JavaScript suporta retornos de chamada muito bem, por exemplo, com lambdas e fechamentos. E há muita atividade no mundo JavaScript, tanto no navegador quanto no servidor. Existem até plataformas JavaScript sendo desenvolvidas para dispositivos móveis.

À medida que avançamos, cada vez mais pessoas escrevem código assíncrono, para o qual esse entendimento será essencial.


1
Um conceito muito bem explicado ..! :)
piyushGoyal

Ótima explicação, +1.
Lingamurthy CS

1
Esta é a melhor resposta entre todas as outras. Voto por favor.
Abhishek Nalin

3
Explicado perfeitamente e tudo é explicado. Eu gostaria de poder votar novamente.
Yogesh Yadav

Sim, eu entendo como lambas funcionam em javascript e ruby. E o java 8, mas as versões antigas do java não usavam lambas e usavam classes, e eu gostaria de saber como esse tipo de retorno de chamada funciona. Ainda uma resposta superior à outra.
Donato

96

Observe que o retorno de chamada é uma palavra.

A página de retorno de chamada da Wikipedia explica muito bem.

citação da página da wikipedia:

Na programação de computadores, um retorno de chamada é uma referência ao código executável, ou uma parte do código executável, que é passada como argumento para outro código. Isso permite que uma camada de software de nível inferior chame uma sub-rotina (ou função) definida em uma camada de nível superior.


14
Ótima maneira de apresentar uma resposta.
Chathuranga Chandrasekara

1
E isso também leva à resposta de uma maneira diferente. O substantivo "retorno de chamada" é aquele que foi "chamado de volta", da mesma forma que algo que foi encerrado foi encerrado e algo que é usado para efetuar login é um login.
Anônimo

22
Isto poderia ter sido um comentário - basicamente é um link para a Wikipedia
CodyBugstein

Na verdade, a Wikipedia tem algumas coisas de programação realmente impressionantes. Eu sempre senti que o termo "retorno de chamada" era melhor explicado usando a frase "eu vou ligar de volta para ..." #
Thomas Thomas

Ótima explicação em javascriptissexy.com/…; que eu vou repassar aqui; Uma função de retorno de chamada é uma função que é passada para outra função como parâmetro, e a função de retorno de chamada é chamada ou executada dentro da outraFunção. // Observe que o item no parâmetro do método click é uma função, não uma variável. // O item é uma função de retorno de chamada $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked" );}); Como você pode ver no exemplo anterior, vamos passar uma função como um parâmetro para o método clique para que ele execute -
MarcoZen

46

Uma resposta leiga seria que é uma função que não é chamada por você, mas pelo usuário ou pelo navegador após um determinado evento ter ocorrido ou depois que algum código foi processado.


42

Uma função de retorno de chamada é aquela que deve ser chamada quando uma determinada condição for atendida. Em vez de ser chamada imediatamente, a função de retorno de chamada é chamada em um determinado ponto no futuro.

Normalmente, é usado quando uma tarefa está sendo iniciada que termina de forma assíncrona (ou seja, termina algum tempo após o retorno da função de chamada).

Por exemplo, uma função para solicitar uma página da Web pode exigir que o chamador forneça uma função de retorno de chamada que será chamada quando a página da Web terminar o download.


Na sua primeira frase, você diz, "...when a condition is met"mas eu pensei que os retornos de chamada são chamados quando a função pai termina a execução e não depende das condições (?).
Ojonugwa Jude Ochalifu

A 'certa condição' significa apenas que eles geralmente são chamados por uma razão, e não aleatoriamente. Um retorno de chamada pode ser chamado quando o pai / criador ainda está em execução - isso pode levar a uma condição de corrida se o programador não o estiver esperando.
22614 Thomas Bratt

Ok. Obrigado pelo esclarecimento
Ojonugwa Jude Ochalifu

34

Os retornos de chamada são descritos com mais facilidade em termos de sistema telefônico. Uma chamada de função é análoga a ligar para alguém no telefone, fazer uma pergunta, obter uma resposta e desligar; adicionar um retorno de chamada altera a analogia para que, depois de fazer uma pergunta, você também forneça seu nome e número para que ela possa ligar de volta com a resposta.

- Paul Jakubik, "Implementações de retorno de chamada em C ++"


1
Então, meu nome e número é uma função?
precisa

Não, essa seria a analogia se "retorno de chamada" fosse um bom nome para o que é: você pede à operadora de telefonia para fazer uma ligação. O fim.
Gherson

33

Acredito que esse jargão de "retorno de chamada" tenha sido usado por engano em muitos lugares. Minha definição seria algo como:

Uma função de retorno de chamada é uma função que você transmite a alguém e permite que ela o chame em algum momento.

Eu acho que as pessoas acabam de ler a primeira frase da definição da wiki:

um retorno de chamada é uma referência ao código executável, ou uma parte do código executável, que é passada como argumento para outro código.

Eu tenho trabalhado com muitas APIs, veja vários exemplos ruins. Muitas pessoas tendem a nomear um ponteiro de função (uma referência ao código executável) ou funções anônimas (uma parte do código executável) de "retorno de chamada", se são apenas funções, por que você precisa de outro nome para isso?

Na verdade, apenas a segunda frase na definição do wiki revela as diferenças entre uma função de retorno de chamada e uma função normal:

Isso permite que uma camada de software de nível inferior chame uma sub-rotina (ou função) definida em uma camada de nível superior.

então a diferença é para quem você vai passar a função e como sua função passada será chamada. Se você acabou de definir uma função e passá-la para outra função e a chamou diretamente no corpo da função, não a chame de retorno de chamada. A definição diz que sua função passada será chamada pela função "nível inferior".

Espero que as pessoas possam parar de usar essa palavra em um contexto ambíguo, isso não pode ajudar as pessoas a entender melhor, apenas pior.


2
Sua resposta faz sentido ... mas estou tendo problemas para imaginá-la. Você pode dar um exemplo?
CodyBugstein

3
@Zane Wong :: No último, você escreveu "A definição diz que sua função passada será chamada pela função" de nível inferior "." Você pode explicar o que a função de nível inferior indica? É melhor se você der um exemplo.
Viku 23/01

Um exemplo teria sido bom
Yousuf Azad

1
Eu acho que a diferença entre a chamada de função clássica e o estilo de retorno de chamada é o link para a direção dependente: se o módulo A depende do módulo B ("usos"), A chama uma função de B, não é um retorno de chamada. Se A passa uma referência à sua função para B, então B chama uma função de A, isto é um retorno de chamada: a chamada retrocede comparando com a dependência do módulo.
XouDo 12/12/19

30

Vamos simplificar. O que é uma função de retorno de chamada?

Exemplo por Parábola e Analogia

Eu tenho uma secretária Todos os dias peço que ela: (i) entregue as correspondências enviadas pela empresa nos correios e, depois que ela o faça, faça: (ii) qualquer tarefa que eu escrevi para ela em uma dessas anotações .

Agora, qual é a tarefa do lembrete? A tarefa varia de dia para dia.

Suponha que nesse dia em particular exija que ela imprima alguns documentos. Então, escrevo isso no bilhete e colo na mesa dela, junto com as correspondências que ela precisa postar.

Em suma:

  1. primeiro, ela precisa deixar o correio e
  2. imediatamente depois disso, ela precisa imprimir alguns documentos.

A função de retorno de chamada é a segunda tarefa: imprimir esses documentos. Porque isso é feito APÓS o e-mail cair, e também porque a nota pegajosa solicitando que ela imprima o documento é fornecida juntamente com o e-mail que ela precisa postar.

Vamos agora ligar isso ao vocabulário de programação

  • O nome do método neste caso é: DropOffMail.
  • E a função de retorno de chamada é: PrintOffDocuments. O PrintOffDocuments é a função de retorno de chamada, porque queremos que a secretária faça isso, somente após a execução do DropOffMail.
  • Então, eu "passaria: PrintOffDocuments como um" argumento "para o método DropOffMail. Este é um ponto importante.

Isso é tudo. Nada mais. Espero que isso tenha esclarecido tudo para você - e, se não, poste um comentário e farei o possível para esclarecer.


18

Isso faz com que os retornos de chamada soem como instruções de retorno no final dos métodos.

Não tenho certeza de que são isso.

Eu acho que os retornos de chamada são realmente uma chamada para uma função, como conseqüência de outra função ser chamada e concluída.

Eu também acho que os retornos de chamada têm como objetivo tratar da invocação originária, em uma espécie de "ei! A coisa que você pediu? Eu fiz isso - apenas pensei em avisar você - de volta para você".


1
+1 para questionar as declarações de retorno versus retorno. Eu costumava ser pego por isso e muitos outros graduados com quem trabalho.
precisa saber é o seguinte

2
Boa resposta - me ajudou a entendê-lo, diferentemente de muitas das outras respostas!
adaam

18

O que é retorno de chamada ?

  • Em geral, uma ligação telefônica feita para retornar uma que alguém recebeu.
  • Na computação, um retorno de chamada é um pedaço de código executável que é passado como argumento para outro código. Quando a função é concluída com seu trabalho (ou quando ocorreu algum evento), ela chama sua função de retorno de chamada (chama de volta - daí o nome).

O que é uma função de retorno de chamada ?

  • uma função de retorno de chamada é como um Servo que "chama de volta" ao seu Mestre quando ele conclui uma tarefa.
  • uma função de retorno de chamada é uma função que é passada para outra função (vamos chamar essa outra função otherFunction) como parâmetro, e a função de retorno de chamada é chamada (ou executada) dentro do otherFunction.
    function action(x, y, callback) {
        return callback(x, y);
    }

    function multiplication(x, y) {
        return x * y;
    }

    function addition(x, y) {
        return x + y;
    }

    alert(action(10, 10, multiplication)); // output: 100

    alert(action(10, 10, addition)); // output: 20

Na SOA, o retorno de chamada permite que os Módulos de Plugin acessem serviços do contêiner / ambiente.

Analogia: retornos de chamada. Assíncrono. Exemplo da vida real sem bloqueio
para retorno de chamada


Uma função de retorno de chamada não é uma função de ordem superior. É passado para uma função de ordem superior.
danio

17

Chamar depois seria um nome melhor do que o nome estúpido, retorno de chamada . Quando ou se a condição for atendida em uma função, chame outra função, a função Chamar Após , aquela recebida como argumento.

Em vez de codificar uma função interna dentro de uma função, alguém escreve uma função para aceitar uma função Call After já escrita como argumento. A chamada após pode ser chamada com base nas alterações de estado detectadas pelo código na função que recebe o argumento.


Esta é uma ótima idéia. Eu fui para "chamado na parte de trás" para tentar explicar isso. Eu pude ver alguém como Martin Fowler popularizando "chamar depois" como um novo termo para eles em seu blog seminal.
8bitjunkie

15

Uma função de retorno de chamada é uma função que você especifica para uma função / método existente, a ser invocada quando uma ação é concluída, requer processamento adicional etc.

Em Javascript, ou mais especificamente jQuery, por exemplo, você pode especificar um argumento de retorno de chamada a ser chamado quando uma animação terminar.

No PHP, a preg_replace_callback()função permite fornecer uma função que será chamada quando a expressão regular for correspondida, passando a (s) string (s) correspondente (s) como argumento.


10

olha a imagem :)é assim que funciona

O programa principal chama a função de biblioteca (que também pode ser uma função no nível do sistema) com o nome da função de retorno de chamada. Essa função de retorno de chamada pode ser implementada de várias maneiras. O programa principal escolhe um retorno de chamada conforme o requisito.

Finalmente, a função de biblioteca chama a função de retorno de chamada durante a execução.


7
Você se importaria de adicionar uma explicação em texto para isso? Se a imagem desaparecer, essa resposta perde todo o contexto.
Tim Post

o texto de outras pessoas explica o melhor. a única coisa que senti que está faltando é a imagem :) #

De todas as longas descrições que vi aqui, essa foi a que me fez dizer "ahhhhh, agora vejo seu uso". Tenha um voto positivo.
DiBosco 29/04/19

7

A resposta simples para essa pergunta é que uma função de retorno de chamada é uma função chamada por meio de um ponteiro de função. Se você passar o ponteiro (endereço) de uma função como argumento para outro, quando esse ponteiro é usado para chamar a função, ele aponta para ele e diz que é feita uma chamada de retorno.


6

Suponha que temos uma função na sort(int *arraytobesorted,void (*algorithmchosen)(void))qual ele pode aceitar um ponteiro de função como argumento, que pode ser usado em algum momento da sort()implementação. Então, aqui o código que está sendo endereçado pelo ponteiro da função algorithmchosené chamado como função de retorno de chamada .

E veja a vantagem é que podemos escolher qualquer algoritmo como:

  1.    algorithmchosen = bubblesort
  2.    algorithmchosen = heapsort
  3.    algorithmchosen = mergesort   ...

Quais foram, digamos, implementados com o protótipo:

  1.   `void bubblesort(void)`
  2.   `void heapsort(void)`
  3.   `void mergesort(void)`   ...

Este é um conceito usado para obter polimorfismo na programação orientada a objetos


Ótima explicação em javascriptissexy.com/…; que eu vou repassar aqui; Uma função de retorno de chamada é uma função que é passada para outra função como parâmetro, e a função de retorno de chamada é chamada ou executada dentro da outraFunção. // Observe que o item no parâmetro do método click é uma função, não uma variável. // O item é uma função de retorno de chamada $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked" );}); Como você pode ver no exemplo anterior, vamos passar uma função como um parâmetro para o método clique para que ele execute -
MarcoZen

4

“Na programação de computadores, um retorno de chamada é uma referência ao código executável, ou um pedaço de código executável, que é passado como argumento para outro código. Isso permite que uma camada de software de nível inferior chame uma sub-rotina (ou função) definida em uma camada de nível superior. ” - Wikipedia

Retorno de chamada em C usando o ponteiro de função

Em C, o retorno de chamada é implementado usando o Ponteiro de Função. Ponteiro de função - como o nome sugere, é um ponteiro para uma função.

Por exemplo, int (* ptrFunc) ();

Aqui, ptrFunc é um ponteiro para uma função que não aceita argumentos e retorna um número inteiro. NÃO esqueça de colocar parênteses, caso contrário, o compilador assumirá que ptrFunc é um nome de função normal, que não aceita nada e retorna um ponteiro para um número inteiro.

Aqui está um código para demonstrar o ponteiro da função.

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

Agora vamos tentar entender o conceito de retorno de chamada em C usando o ponteiro de função.

O programa completo possui três arquivos: callback.c, reg_callback.he reg_callback.c.

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

Se rodarmos este programa, a saída será

Este é um programa que demonstra a função de retorno de chamada dentro de register_callback dentro de my_callback de volta no programa principal

A função de camada superior chama uma função de camada inferior como uma chamada normal e o mecanismo de retorno de chamada permite que a função de camada inferior chame a função de camada superior através de um ponteiro para uma função de retorno de chamada.

Retorno de chamada em Java usando a interface

Java não possui o conceito de ponteiro de função. Implementa o mecanismo de retorno de chamada através do seu mecanismo de interface. Aqui, em vez de um ponteiro de função, declaramos uma interface com um método que será chamado quando o destinatário concluir sua tarefa.

Deixe-me demonstrá-lo através de um exemplo:

A interface de retorno de chamada

public interface Callback
{
    public void notify(Result result);
}

O chamador ou a classe de nível superior

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

A função Callee ou a camada inferior

public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}

Retorno de Chamada Usando o Padrão EventListener

  • Item da lista

Esse padrão é usado para notificar de 0 a n números de Observadores / Ouvintes que uma tarefa específica foi concluída

  • Item da lista

A diferença entre o mecanismo de retorno de chamada e o mecanismo EventListener / Observer é que, no retorno de chamada, o destinatário notifica o chamador único, enquanto no Eventlisener / Observer, o destinatário pode notificar qualquer pessoa interessada nesse evento (a notificação pode ir para outras partes do aplicativo que não acionou a tarefa)

Deixe-me explicar através de um exemplo.

A interface do evento

public interface Events {

public void clickEvent();
public void longClickEvent();
}

Widget de classe

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

Botão Classe

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

Caixa de seleção Classe

public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}

Classe de atividade

pacote com.som_itsolutions.training.java.exampleeventlistener;

public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}

Outra classe

public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}

Classe principal

public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}

Como você pode ver no código acima, temos uma interface chamada events que basicamente lista todos os eventos que podem acontecer para nosso aplicativo. A classe Widget é a classe base de todos os componentes da interface do usuário, como botão e caixa de seleção. Esses componentes da interface do usuário são os objetos que realmente recebem os eventos do código da estrutura. A classe Widget implementa a interface Events e também possui duas interfaces aninhadas, a saber, OnClickEventListener e OnLongClickEventListener

Essas duas interfaces são responsáveis ​​por ouvir os eventos que podem ocorrer nos componentes da interface do usuário derivados do Widget, como Botão ou Caixa de seleção. Portanto, se compararmos este exemplo com o exemplo anterior de retorno de chamada usando a interface Java, essas duas interfaces funcionarão como a interface de retorno de chamada. Portanto, o código de nível superior (Atividade aqui) implementa essas duas interfaces. E sempre que um evento ocorrer em um widget, o código de nível superior (ou o método dessas interfaces implementadas no código de nível superior, que é aqui Atividade) será chamado.

Agora, deixe-me discutir a diferença básica entre o padrão de retorno de chamada e ouvinte de evento. Como mencionamos, usando o retorno de chamada, o Callee pode notificar apenas um único chamador. Porém, no caso do padrão EventListener, qualquer outra parte ou classe do Aplicativo pode se registrar para os eventos que podem ocorrer no Botão ou na Caixa de Seleção. O exemplo desse tipo de classe é o OtherClass. Se você vir o código da OtherClass, descobrirá que ele se registrou como ouvinte do ClickEvent que pode ocorrer no botão definido na Atividade. Parte interessante é que, além da Atividade (o chamador), essa OtherClass também será notificada sempre que o evento click ocorrer no botão.


Por favor ligação evite só responde . As respostas que são "pouco mais que um link para um site externo" podem ser excluídas .
Quentin

3

Uma função de retorno de chamada é uma função que você passa (como referência ou ponteiro) para uma determinada função ou objeto. Essa função ou objeto chamará essa função de volta a qualquer momento mais tarde, possivelmente várias vezes, para qualquer tipo de finalidade:

  • notificando o fim de uma tarefa
  • solicitando comparação entre dois itens (como em c qsort ())
  • relatar o progresso de um processo
  • notificando eventos
  • delegando a instanciação de um objeto
  • delegando a pintura de uma área

...

Portanto, descrever um retorno de chamada como uma função chamada no final de outra função ou tarefa é muito simplificador (mesmo que seja um caso de uso comum).


2

Um retorno de chamada é uma ideia de passar uma função como parâmetro para outra função e invocá-la assim que o processo for concluído.

Se você obtiver o conceito de retorno de chamada através das respostas impressionantes acima, recomendo que você aprenda os antecedentes de sua ideia.

"O que os fez (cientistas da computação) desenvolver retorno de chamada?" Você pode aprender um problema que está bloqueando. (Especialmente o bloqueio da interface do usuário) E o retorno de chamada não é a única solução para ele. Existem muitas outras soluções (por exemplo: Thread, Futures, Promises ...).


1

Uma área de uso importante é que você registre uma de suas funções como identificador (ou seja, um retorno de chamada) e depois envie uma mensagem / chamada para alguma função para realizar algum trabalho ou processamento. Agora, após o término do processamento, a função chamada chamaria nossa função registrada (ou seja, agora a chamada de retorno está concluída), indicando que o processamento está concluído.
Este link da wikipedia explica muito bem graficamente.


1

Uma função de retorno de chamada, também conhecida como função de ordem superior, é uma função que é passada para outra função como parâmetro, e a função de retorno de chamada é chamada (ou executada) dentro da função pai.

$("#button_1").click(function() {
  alert("button 1 Clicked");
});

Aqui passamos uma função como parâmetro para o método click. E o método click chamará (ou executará) a função de retorno de chamada que passamos para ele.


1
Uma função de retorno de chamada não é uma função de ordem superior. É passado para uma função de ordem superior.
danio

1

Função de retorno de chamada Uma função que passou para outra função como argumento.

function test_function(){       
 alert("Hello world");  
} 

setTimeout(test_function, 2000);

Nota: No exemplo acima test_function usado como argumento para a função setTimeout.


1
Bem-vindo ao Stack Overflow! Antes de responder a uma pergunta, sempre leia as respostas existentes. Esta resposta já foi fornecida. Em vez de repetir a resposta, vote na resposta existente. Algumas diretrizes para escrever boas respostas podem ser encontradas aqui .
Dferenc
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.