¿Qué es una función de devolución de llamada?

684

¿Qué es una función de devolución de llamada?

Cheekysoft
fuente
8
puede encontrar aquí: stackoverflow.com/a/9652434/3343174 la mejor explicación sobre las devoluciones de llamada
Fakher
Mire la segunda respuesta para obtener una explicación detallada
Donato
La mejor explicación de devolución de llamada que he encontrado youtube.com/watch?v=xHneyv38Jro
Sameer Sinha

Respuestas:

681

Los desarrolladores a menudo se confunden por lo que es una devolución de llamada debido al nombre de la maldita cosa.

Una función de devolución de llamada es una función que es:

  • accesible por otra función, y
  • se invoca después de la primera función si esa primera función se completa

Una buena manera de imaginar cómo funciona una función de devolución de llamada es que es una función que se " llama en la parte posterior " de la función a la que se pasa.

Tal vez un mejor nombre sería una función de "llamada después" .

Esta construcción es muy útil para el comportamiento asíncrono donde queremos que tenga lugar una actividad cada vez que se completa un evento anterior.

Pseudocó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 si llamó a event ():

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

El orden de la salida aquí es importante. Dado que las funciones de devolución de llamada se llaman después, "He terminado de imprimir números" se imprime en último lugar, no primero.

Las devoluciones de llamada se denominan debido a su uso con idiomas de puntero. Si no usa uno de esos, no trabaje con el nombre 'devolución de llamada'. Solo comprenda que es solo un nombre para describir un método que se proporciona como argumento para otro método, de modo que cuando se llama al método principal (cualquier condición, como un clic en un botón, un tic del temporizador, etc.) y su cuerpo del método se completa, se invoca la función de devolución de llamada.

Algunos idiomas admiten construcciones en las que se admiten múltiples argumentos de función de devolución de llamada, y se invocan en función de cómo se completa la función principal (es decir, se llama a una devolución de llamada en caso de que la función principal se complete con éxito, se llama a otra en caso de que la función principal arroje un error específico, etc.)

8bitjunkie
fuente
31
Su ejemplo es excelente, pero no veo por qué la terminología es "devolución de llamada". ¿Cuándo se "devuelve" el significado de LifeLfLife?
CodyBugstein
44
Hola a todos once its parent method completes, the function which this argument represents is then called. Entonces, si la función se pasa a otra función como argumento pero se llama desde la mitad del tiempo de ejecución de la función principal, ¿ parent(cb) {dostuff1(); cb(); dostuff2()}entonces no se considera una callbackfunción?
Max Yari
2
@MaxYari: En mi humilde opinión, todavía se considera como devolución de llamada. Lo importante aquí es que la función principal utilizará la función de entrada (también conocida como devolución de llamada) de alguna manera. Se puede llamar en el medio o al final o si se cumple una condición.
Kamran Bigdely
12
@ 8bitjunkie gracias, pero ¿dónde se invoca el método meaningOfLife dentro de la función printANumber?
BKSpurgeon
2
Esto no es cierto en absoluto: "se invoca automáticamente después de que se completa esa primera función". Una devolución de llamada no tiene que ejecutarse en absoluto, y mucho menos automáticamente. De hecho, no es raro que se completen las devoluciones de llamada antes de que se complete la función principal. No me gusta mucho cómo la gente describe las devoluciones de llamada como funciones que se ejecutan "más tarde". Es muy confuso para las personas que están aprendiendo sobre ellos. En pocas palabras, las devoluciones de llamada son solo funciones que se pasan como argumentos a otras funciones. Período. Una mejor explicación incluiría explicar POR QUÉ las devoluciones de llamada sobre las referencias de funciones.
Jordan
225

Definición opaca

Una función de devolución de llamada es una función que usted proporciona a otro fragmento de código, lo que le permite ser invocado por ese código.

Ejemplo contribuido

Por qué querrías hacer esto? Digamos que hay un servicio que necesita invocar. Si el servicio regresa de inmediato, simplemente:

  1. Llámalo
  2. Espera el resultado
  3. Continuar una vez que llegue el resultado

Por ejemplo, supongamos que el servicio fuera la factorialfunción. Cuando desee el valor de 5!, invocaría factorial(5)y se darían los siguientes pasos:

  1. Su ubicación de ejecución actual se guarda (en la pila, pero eso no es importante)

  2. La ejecución se entrega a factorial

  3. Cuando se factorialcompleta, coloca el resultado en algún lugar al que pueda llegar

  4. La ejecución vuelve a donde estaba [1]

Ahora suponga que factorialtomó mucho tiempo, porque le está dando grandes cantidades y necesita ejecutarse en algún clúster de supercomputación en algún lugar. Digamos que espera que le tome 5 minutos devolver su resultado. Tú podrías:

  1. Mantenga su diseño y ejecute su programa por la noche cuando esté dormido, para que no esté mirando la pantalla la mitad del tiempo

  2. Diseñe su programa para hacer otras cosas mientras factorialhace lo suyo

Si elige la segunda opción, las devoluciones de llamada podrían funcionar para usted.

Diseño de extremo a extremo

Para explotar un patrón de devolución de llamada, lo que desea es poder llamar factorialde la siguiente manera:

factorial(really_big_number, what_to_do_with_the_result)

El segundo parámetro, what_to_do_with_the_resultes una función a la que envía factorial, con la esperanza de que factoriallo llame a su resultado antes de regresar.

Sí, esto significa que factorialdebe haber sido escrito para admitir devoluciones de llamada.

Ahora suponga que desea poder pasar un parámetro a su devolución de llamada. Ahora no puedes, porque no lo vas a llamar, factoriales. Por lo tanto factorial, debe escribirse para permitirle pasar sus parámetros, y simplemente los entregará a su devolución de llamada cuando lo invoque. Podría verse así:

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

Ahora que factorialpermite este patrón, su devolución de llamada podría verse así:

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

y tu llamada factorialsería

factorial(42, logIt, logger)

¿Qué pasa si quieres devolver algo logIt? Bueno, no puedes, porque factorialno le estás prestando atención.

Bueno, ¿por qué no puede factorialdevolver lo que devuelve su devolución de llamada?

Haciéndolo sin bloqueo

Dado que la ejecución debe entregarse a la devolución de llamada cuando factorialfinalice, realmente no debería devolver nada a la persona que llama. E idealmente, de alguna manera iniciaría su trabajo en otro hilo / proceso / máquina y regresaría de inmediato para que pueda continuar, tal vez algo como esto:

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

Esta es ahora una "llamada asincrónica", lo que significa que cuando la llamas, regresa de inmediato pero aún no ha hecho su trabajo. Por lo tanto, necesita mecanismos para verificarlo y obtener su resultado cuando finalice, y su programa se ha vuelto más complejo en el proceso.

Y, por cierto, utilizando este patrón, factorial_worker_taskpuede iniciar su devolución de llamada de forma asincrónica y regresar de inmediato.

Entonces, ¿Qué haces?

La respuesta es permanecer dentro del patrón de devolución de llamada. Cuando quieras escribir

a = f()
g(a)

y fse llamará asincrónicamente, en su lugar escribirá

f(g)

donde gse pasa como una devolución de llamada.

Esto cambia fundamentalmente la topología de flujo de su programa y lleva un tiempo acostumbrarse.

Su lenguaje de programación podría ayudarlo mucho al brindarle una forma de crear funciones sobre la marcha. En el código inmediatamente anterior, la función gpuede ser tan pequeña como print (2*a+1). Si su idioma requiere que defina esto como una función separada, con un nombre y una firma completamente innecesarios, entonces su vida se volverá desagradable si usa mucho este patrón.

Si, por otro lado, tu idioma te permite crear lambdas, entonces estás en mejor forma. Luego terminarás escribiendo algo como

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

que es mucho mejor

Cómo pasar la devolución de llamada

¿Cómo pasarías la función de devolución de llamada factorial? Bueno, podrías hacerlo de varias maneras.

  1. Si la función llamada se ejecuta en el mismo proceso, puede pasar un puntero de función

  2. O tal vez desee mantener un diccionario de fn name --> fn ptren su programa, en cuyo caso podría pasar el nombre

  3. ¡Quizás su lenguaje le permita definir la función en el lugar, posible como una lambda! Internamente está creando algún tipo de objeto y pasando un puntero, pero no tiene que preocuparse por eso.

  4. Quizás la función que está llamando se ejecuta en una máquina completamente separada, y la está llamando usando un protocolo de red como HTTP. Puede exponer su devolución de llamada como una función invocable HTTP y pasar su URL.

Tienes la idea.

El reciente aumento de las devoluciones de llamada

En esta era web en la que hemos ingresado, los servicios que invocamos a menudo se realizan a través de la red. A menudo no tenemos ningún control sobre esos servicios, es decir, no los escribimos, no los mantenemos, no podemos asegurarnos de que estén funcionando o de cómo están funcionando.

Pero no podemos esperar que nuestros programas se bloqueen mientras esperamos que estos servicios respondan. Teniendo esto en cuenta, los proveedores de servicios a menudo diseñan API utilizando el patrón de devolución de llamada.

JavaScript admite devoluciones de llamada muy bien, por ejemplo, con lambdas y cierres. Y hay mucha actividad en el mundo de JavaScript, tanto en el navegador como en el servidor. Incluso se están desarrollando plataformas JavaScript para dispositivos móviles.

A medida que avanzamos, más y más de nosotros escribiremos código asincrónico, para lo cual esta comprensión será esencial.

Rohit Chatterjee
fuente
1
Un concepto muy bien explicado ..! :)
piyushGoyal
Gran explicación, +1.
Lingamurthy CS
1
Esta es la mejor respuesta entre todas las demás. Votarlo amablemente.
Abhishek Nalin
3
Explica perfectamente y todo se explica. Desearía poder votar de nuevo.
Yogesh Yadav
Sí, entiendo cómo funcionan las lambas en JavaScript y Ruby. Y java 8, pero las versiones antiguas de java no usaban lambas y en su lugar usaban clases y me gustaría saber cómo funciona ese tipo de devolución de llamada. Sigue siendo una respuesta superior a la otra.
Donato
97

Tenga en cuenta que la devolución de llamada es una palabra.

La página de devolución de llamada de Wikipedia lo explica muy bien.

cita de la página de wikipedia:

En la programación de computadoras, una devolución de llamada es una referencia al código ejecutable, o un fragmento de código ejecutable, que se pasa como argumento a otro código. Esto permite que una capa de software de nivel inferior llame a una subrutina (o función) definida en una capa de nivel superior.

danio
fuente
14
Buena manera de presentar una respuesta.
Chathuranga Chandrasekara
1
Y esto también lleva a la respuesta de una manera diferente. El sustantivo "devolución de llamada" es el que ha sido "devuelto", de la misma manera que algo que ha pasado por apagado se ha cerrado y algo que se utiliza para iniciar sesión es un inicio de sesión.
Anónimo
22
Esto podría haber sido un comentario - básicamente es un enlace a Wikipedia
CodyBugstein
Wikipedia en realidad tiene algunas cosas de programación realmente increíbles en sus tesoros. Siempre sentí que el término "devolución de llamada" se explicaba mejor usando la frase "voy a volver a llamar para ..."
Thomas
Gran explicación en javascriptissexy.com/…; que volveré a publicar aquí; Una función de devolución de llamada es una función que se pasa a otra función como parámetro, y la función de devolución de llamada se llama o ejecuta dentro de la otra función. // Tenga en cuenta que el elemento en el parámetro del método click es una función, no una variable. // El elemento es una función de devolución de llamada $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked" );}); Como puede ver en el ejemplo anterior, pasamos una función como parámetro al método de clic para que se ejecute -
MarcoZen
46

Una respuesta simple sería que es una función que no es invocada por usted, sino por el usuario o por el navegador después de que cierto evento haya sucedido o después de que se haya procesado algún código.

NateH
fuente
42

Una función de devolución de llamada es aquella que debe llamarse cuando se cumple una determinada condición. En lugar de ser llamado de inmediato, la función de devolución de llamada se llama en un momento determinado en el futuro.

Por lo general, se usa cuando se inicia una tarea que finalizará de forma asincrónica (es decir, finalizará algún tiempo después de que la función de llamada haya regresado).

Por ejemplo, una función para solicitar una página web puede requerir que la persona que llama proporcione una función de devolución de llamada que se llamará cuando la página web haya finalizado la descarga.

Thomas Bratt
fuente
En su primera oración, usted dice "...when a condition is met"pero pensé que las devoluciones de llamada se llaman cuando la función principal termina de ejecutarse y no dependen de las condiciones (?).
Ojonugwa Jude Ochalifu
La 'cierta condición' solo significa que generalmente se les llama por una razón, en lugar de al azar. Se puede llamar a una devolución de llamada cuando el padre / creador todavía se está ejecutando; esto podría conducir a una condición de carrera si el programador no lo espera.
Thomas Bratt
Bien. Gracias por la aclaración
Ojonugwa Jude Ochalifu
34

Las devoluciones de llamada se describen más fácilmente en términos del sistema telefónico. Una llamada de función es análoga a llamar a alguien por teléfono, hacerle una pregunta, obtener una respuesta y colgar; agregar una devolución de llamada cambia la analogía para que después de hacerle una pregunta, también le dé su nombre y número para que pueda devolverle la llamada con la respuesta.

- Paul Jakubik, "Implementaciones de devolución de llamada en C ++"

DejanLekic
fuente
1
¿Entonces mi nombre y número es una función?
Koray Tugay
No, esa sería la analogía si "devolución de llamada" fuera un buen nombre para lo que es en su lugar: le pide al operador telefónico que haga una llamada. El fin.
gherson
33

Creo que esta jerga de "devolución de llamada" se ha utilizado por error en muchos lugares. Mi definición sería algo como:

Una función de devolución de llamada es una función que le pasa a alguien y le permite llamarla en algún momento.

Creo que la gente acaba de leer la primera oración de la definición de wiki:

una devolución de llamada es una referencia al código ejecutable, o un fragmento de código ejecutable, que se pasa como argumento a otro código.

He estado trabajando con muchas API, veo varios ejemplos malos. Muchas personas tienden a nombrar un puntero de función (una referencia al código ejecutable) o funciones anónimas (una pieza de código ejecutable) "devolución de llamada", si son solo funciones, ¿por qué necesita otro nombre para esto?

En realidad, solo la segunda oración en la definición de wiki revela las diferencias entre una función de devolución de llamada y una función normal:

Esto permite que una capa de software de nivel inferior llame a una subrutina (o función) definida en una capa de nivel superior.

así que la diferencia es a quién va a pasar la función y cómo se llamará a su función pasada. Si solo define una función y la pasa a otra función y la llamó directamente en ese cuerpo de función, no la llame devolución de llamada. La definición dice que su función aprobada será llamada por la función de "nivel inferior".

Espero que la gente pueda dejar de usar esta palabra en un contexto ambiguo, no puede ayudar a las personas a entender mejor, solo peor.

Zane XY
fuente
2
Tu respuesta tiene sentido ... pero tengo problemas para imaginarla. ¿Puede dar un ejemplo?
CodyBugstein
3
@Zane Wong :: En el último que ha escrito "La definición dice que su función aprobada será llamada por la función de" nivel inferior ". ¿Puede explicar qué indica la función de nivel inferior? Es mejor si das un ejemplo.
Viku
Un ejemplo hubiera sido bueno
Yousuf Azad
1
Creo que la diferencia entre la función clásica de llamada y el estilo de devolución de llamada es el enlace a la dirección de dependencia: si el módulo A depende del módulo B ("usa"), A llama a una función de B, no es una devolución de llamada. Si A pasa una referencia a su función a B, entonces B llama a una función de A, esto es una devolución de llamada: la llamada retrocede en comparación con la dependencia del módulo.
XouDo
30

Hagámoslo simple. ¿Qué es una función de devolución de llamada?

Ejemplo por parábola y analogía

Tengo una secretaria Todos los días le pido que: (i) deje el correo saliente de la empresa en la oficina de correos, y después de que lo haya hecho, haga: (ii) cualquier tarea que le escribí en una de esas notas adhesivas .

Ahora, ¿cuál es la tarea en la nota adhesiva? La tarea varía de un día a otro.

Supongamos que en este día en particular, le exijo que imprima algunos documentos. Así que lo escribo en la nota adhesiva, y lo pongo en su escritorio junto con el correo saliente que necesita publicar.

En resumen:

  1. primero, ella necesita dejar el correo y
  2. Inmediatamente después de hacerlo, ella necesita imprimir algunos documentos.

La función de devolución de llamada es esa segunda tarea: imprimir esos documentos. Debido a que se hace DESPUÉS de que se deja el correo, y también porque se le entrega la nota adhesiva que le dice que imprima el documento junto con el correo que necesita publicar.

Ahora relacionemos esto con el vocabulario de programación

  • El nombre del método en este caso es: DropOffMail.
  • Y la función de devolución de llamada es: PrintOffDocuments. PrintOffDocuments es la función de devolución de llamada porque queremos que la secretaria lo haga, solo después de que se haya ejecutado DropOffMail.
  • Entonces "pasaría: PrintOffDocuments como un" argumento "al método DropOffMail. Este es un punto importante.

Eso es todo lo que es. Nada mas. Espero que eso lo haya aclarado, y si no, publique un comentario y haré todo lo posible para aclararlo.

BKSpurgeon
fuente
18

Esto hace que las devoluciones de llamada suenen como declaraciones de retorno al final de los métodos.

No estoy seguro de que sean eso.

Creo que las devoluciones de llamada son en realidad una llamada a una función, como consecuencia de que se invoca y completa otra función.

También creo que las devoluciones de llamada están destinadas a abordar la invocación de origen, en una especie de "¡oye! ¿Qué es lo que pediste?

Mauritico
fuente
1
+1 para cuestionar devoluciones de llamada vs declaraciones de devolución. Solía ​​quedar atrapado por esto y también muchos graduados con los que trabajo.
8bitjunkie
2
Buena respuesta: ¡me ayudó a entenderla, a diferencia de muchas de las otras respuestas!
adaam
18

¿Qué es la devolución de llamada ?

  • En general, una llamada telefónica hecha para devolver una que alguien ha recibido.
  • En informática, una devolución de llamada es un fragmento de código ejecutable que se pasa como argumento a otro código. Cuando la función termina con su trabajo (o cuando ocurre algún evento), llama a su función de devolución de llamada (le devuelve la llamada, de ahí el nombre).

¿Qué es una función de devolución de llamada ?

  • una función de devolución de llamada es como un Servidor que "devuelve la llamada" a su Maestro cuando ha completado una tarea.
  • una función de devolución de llamada es una función que se pasa a otra función (llamemos a esta otra función otherFunction) como un parámetro, y la función de devolución de llamada se llama (o ejecuta) dentro del 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

En SOA, la devolución de llamada permite que los módulos de complemento accedan a los servicios desde el contenedor / entorno.

Analogía: devoluciones de llamada. Asincrónico. Ejemplo de la vida real sin bloqueo
para devolución de llamada

Premraj
fuente
Una función de devolución de llamada no es en sí misma una función de orden superior. Se pasa a una función de orden superior.
danio
17

Call After sería un nombre mejor que el nombre estúpido, callback . Cuando o si la condición se cumple dentro de una función, llame a otra función, la función Llamar después , la recibida como argumento.

En lugar de codificar una función interna dentro de una función, se escribe una función para aceptar una función Call After ya escrita como argumento. Se puede llamar a Call After en función de los cambios de estado detectados por el código en la función que recibe el argumento.

Smack MacDougal
fuente
Esta es una gran idea. Fui a "llamado en la parte de atrás" para tratar de explicar esto. Pude ver a alguien como Martin Fowler popularizando "llamar después" como un nuevo término para estos en su blog seminal.
8bitjunkie
15

Una función de devolución de llamada es una función que usted especifica a una función / método existente, que se invoca cuando se completa una acción, requiere un procesamiento adicional, etc.

En Javascript, o más específicamente jQuery, por ejemplo, puede especificar un argumento de devolución de llamada que se llamará cuando haya finalizado una animación.

En PHP, la preg_replace_callback()función le permite proporcionar una función que se llamará cuando se coincida la expresión regular, pasando la (s) cadena (s) coincidentes como argumentos.

alex
fuente
10

mira la imagen :)Así es como funciona

El programa principal llama a la función de biblioteca (que también podría ser una función de nivel de sistema) con el nombre de la función de devolución de llamada. Esta función de devolución de llamada podría implementarse de varias maneras. El programa principal elige una devolución de llamada según el requisito.

Finalmente, la función de biblioteca llama a la función de devolución de llamada durante la ejecución.

Saumya Suhagiya
fuente
77
¿Te importaría también agregar una explicación de texto a esto? Si la imagen desaparece, esta respuesta pierde todo el contexto.
Tim Post
el texto de otras personas lo explica mejor. lo único que sentí que me falta es la imagen :)
De todas las largas descripciones que he visto aquí, esta es la que me hizo decir "ahhhhh, ahora veo su uso". Tener un voto a favor.
DiBosco
7

La respuesta simple a esta pregunta es que una función de devolución de llamada es una función que se llama a través de un puntero de función. Si pasa el puntero (dirección) de una función como argumento a otra, cuando ese puntero se usa para llamar a la función a la que apunta, se dice que se realiza una devolución de llamada

Zain Ali
fuente
6

Supongamos que tenemos una función sort(int *arraytobesorted,void (*algorithmchosen)(void))en la que puede aceptar un puntero de función como argumento que puede usarse en algún momento de sort()la implementación. Entonces, aquí el código al que se dirige el puntero de función algorithmchosense llama como función de devolución de llamada .

Y ver la ventaja es que podemos elegir cualquier algoritmo como:

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

Los cuales, por ejemplo, se han implementado con el prototipo:

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

Este es un concepto utilizado para lograr el polimorfismo en la programación orientada a objetos.

Neeraj
fuente
Gran explicación en javascriptissexy.com/…; que volveré a publicar aquí; Una función de devolución de llamada es una función que se pasa a otra función como parámetro, y la función de devolución de llamada se llama o ejecuta dentro de la otra función. // Tenga en cuenta que el elemento en el parámetro del método click es una función, no una variable. // El elemento es una función de devolución de llamada $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked" );}); Como puede ver en el ejemplo anterior, pasamos una función como parámetro al método de clic para que se ejecute -
MarcoZen
4

“En la programación de computadoras, una devolución de llamada es una referencia al código ejecutable, o un fragmento de código ejecutable, que se pasa como argumento a otro código. Esto permite que una capa de software de nivel inferior llame a una subrutina (o función) definida en una capa de nivel superior ". - Wikipedia

Devolución de llamada en C usando el puntero de función

En C, la devolución de llamada se implementa utilizando el puntero de función. Puntero de función: como su nombre indica, es un puntero a una función.

Por ejemplo, int (* ptrFunc) ();

Aquí, ptrFunc es un puntero a una función que no toma argumentos y devuelve un entero. NO olvide poner el paréntesis, de lo contrario, el compilador supondrá que ptrFunc es un nombre de función normal, que no toma nada y devuelve un puntero a un entero.

Aquí hay un código para demostrar el puntero de la función.

#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;
}

Ahora intentemos comprender el concepto de devolución de llamada en C usando el puntero de función.

El programa completo tiene tres archivos: callback.c, reg_callback.h y 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)();                               
}

Si ejecutamos este programa, la salida será

Este es un programa que muestra la función de devolución de llamada dentro de register_callback dentro de my_callback dentro del programa principal

La función de capa superior llama a una función de capa inferior como una llamada normal y el mecanismo de devolución de llamada permite que la función de capa inferior llame a la función de capa superior a través de un puntero a una función de devolución de llamada.

Devolución de llamada en Java usando la interfaz

Java no tiene el concepto de puntero de función Implementa el mecanismo de devolución de llamada a través de su mecanismo de interfaz Aquí, en lugar de un puntero de función, declaramos que una interfaz tiene un método que se llamará cuando el destinatario finalice su tarea

Permítanme demostrarlo a través de un ejemplo:

La interfaz de devolución de llamada

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

La persona que llama o la clase de nivel 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
}
}

La función Callee o la capa 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
}
}

Devolución de llamada utilizando el patrón EventListener

  • Elemento de la lista

Este patrón se utiliza para notificar de 0 a n números de observadores / oyentes que una tarea en particular ha finalizado

  • Elemento de la lista

La diferencia entre el mecanismo de devolución de llamada y el mecanismo EventListener / Observer es que en la devolución de llamada, la persona que llama notifica a la persona que llama, mientras que en Eventlisener / Observer, la persona que llama puede notificar a cualquier persona interesada en ese evento (la notificación puede ir a otras partes del aplicación que no ha activado la tarea)

Déjame explicarte a través de un ejemplo.

La interfaz de eventos

public interface Events {

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

Widget de clase

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ón de clase

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

Casilla de verificación de clase

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;
}
}

Clase de actividad

paquete 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();
    }   
}

Otra clase

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

Clase 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 puede ver en el código anterior, tenemos una interfaz llamada eventos que básicamente enumera todos los eventos que pueden ocurrir para nuestra aplicación. La clase Widget es la clase base para todos los componentes de la interfaz de usuario, como Button, Checkbox. Estos componentes de la interfaz de usuario son los objetos que realmente reciben los eventos del código marco. La clase de widget implementa la interfaz de eventos y también tiene dos interfaces anidadas, OnClickEventListener y OnLongClickEventListener

Estas dos interfaces son responsables de escuchar los eventos que pueden ocurrir en los componentes de la interfaz de usuario derivados del widget como Button o Checkbox. Entonces, si comparamos este ejemplo con el ejemplo anterior de devolución de llamada utilizando la interfaz Java, estas dos interfaces funcionan como la interfaz de devolución de llamada. Entonces el código de nivel superior (Here Activity) implementa estas dos interfaces. Y cada vez que se produzca un evento en un widget, se llamará al código de nivel superior (o al método de estas interfaces implementado en el código de nivel superior, que es aquí Actividad).

Ahora déjenme discutir la diferencia básica entre Callback y el patrón Eventlistener. Como hemos mencionado que usando la devolución de llamada, la persona que llama puede notificar solo a una sola persona que llama. Pero en el caso del patrón EventListener, cualquier otra parte o clase de la Aplicación puede registrarse para los eventos que pueden ocurrir en el Botón o Casilla de verificación. El ejemplo de este tipo de clase es el OtherClass. Si ve el código de la Otra Clase, encontrará que se ha registrado como un oyente del ClickEvent que puede ocurrir en el Botón definido en la Actividad. La parte interesante es que, además de la Actividad (la persona que llama), esta Otra Clase también se notificará cada vez que ocurra el evento de clic en el Botón.

somenath mukhopadhyay
fuente
Por favor, evite las respuestas de enlace solamente . Respuestas que son "poco más que un enlace a un sitio externo” se pueden eliminar .
Quentin
3

Una función de devolución de llamada es una función que pasa (como referencia o puntero) a una determinada función u objeto. Esta función u objeto volverá a llamar a esta función en cualquier momento posterior, posiblemente varias veces, para cualquier tipo de propósito:

  • notificar el final de una tarea
  • solicitando una comparación entre dos elementos (como en c qsort ())
  • informar el progreso de un proceso
  • eventos de notificación
  • delegar la instanciación de un objeto
  • delegar la pintura de un área

...

Por lo tanto, describir una devolución de llamada como una función que se llama al final de otra función o tarea es demasiado simplificado (incluso si es un caso de uso común).

XouDo
fuente
2

Una devolución de llamada es una idea de pasar una función como parámetro a otra función y hacer que se invoque una vez que el proceso se haya completado.

Si obtiene el concepto de devolución de llamada a través de respuestas impresionantes anteriores, le recomiendo que conozca los antecedentes de su idea.

"¿Qué los hizo (informáticos) desarrollar devolución de llamada?" Es posible que aprenda un problema, que es el bloqueo (especialmente el bloqueo de la interfaz de usuario) y la devolución de llamada no es la única solución. Hay muchas otras soluciones (por ejemplo: Hilo, Futuros, Promesas ...).

Yoji Yamamoto
fuente
1

Un área de uso importante es que registre una de sus funciones como identificador (es decir, una devolución de llamada) y luego envíe un mensaje / llame a alguna función para realizar algún trabajo o procesamiento. Ahora, después de que se realiza el procesamiento, la función llamada llamará a nuestra función registrada (es decir, ahora se realiza la devolución de llamada), lo que nos indica que el procesamiento está hecho.
Este enlace de wikipedia explica bastante bien gráficamente.

Chintan Parikh
fuente
1

Una función de devolución de llamada, también conocida como función de orden superior, es una función que se pasa a otra función como parámetro, y la función de devolución de llamada se llama (o ejecuta) dentro de la función principal.

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

Aquí hemos pasado una función como parámetro al método de clic. Y el método click llamará (o ejecutará) la función de devolución de llamada que le pasamos.

chirag20388
fuente
1
Una función de devolución de llamada no es en sí misma una función de orden superior. Se pasa a una función de orden superior.
danio
1

Función de devolución de llamada Una función que pasó a otra función como argumento.

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

setTimeout(test_function, 2000);

Nota: En el ejemplo anterior, test_function se usa como argumento para la función setTimeout.

Garvin
fuente
1
¡Bienvenido a Stack Overflow! Antes de responder una pregunta, siempre lea las respuestas existentes. Esta respuesta ya ha sido proporcionada. En lugar de repetir la respuesta, vote la respuesta existente. Algunas pautas para escribir buenas respuestas se pueden encontrar aquí .
dferenc