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


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


541
2018-05-05 10:18


origen


Respuestas:


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 forma de imaginar cómo funciona una función de devolución de llamada es que es una función que es "llamado en la parte posterior"de la función en la que se pasa.

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

Esta construcción es muy útil para el comportamiento asíncrono en el que queremos que tenga lugar una actividad cada vez que se complete 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ó evento ():

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

El orden de la salida aquí es importante. Como las funciones de devolución de llamada se invocan después, "Se terminaron los números de impresión" se imprime al final, no primero.

Las retrollamadas se llaman debido a su uso con idiomas de puntero. Si no usa uno de esos, no trabaje sobre el nombre 'devolución de llamada'. Simplemente entienda 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 de botón, un tic del temporizador, etc.) y su cuerpo de método finaliza, la función de devolución de llamada se invoca entonces.

Algunos lenguajes admiten construcciones donde 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 una devolución de llamada en caso de que la función principal se complete satisfactoriamente, se invoca otra en caso de que la función principal arroje un error específico, etc.).


527
2017-09-26 01:04



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 llamado por ese código.

Ejemplo de ejemplo

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

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

Por ejemplo, supongamos que el servicio fuera el factorial función. Cuando quieres el valor de 5!, invocarías factorial(5), y los siguientes pasos ocurrirían:

  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 factorial completa, pone el resultado en algún lugar al que puedas llegar

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

Ahora supongamos factorial tomó mucho tiempo, porque le está dando un gran número y necesita ejecutarse en algún clúster de supercomputación en alguna parte. Supongamos que espera 5 minutos para devolver el resultado. Tú podrías:

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

  2. Diseña tu programa para hacer otras cosas mientras factorial está haciendo su cosa

Si eliges la segunda opción, entonces las devoluciones de llamadas podrían funcionar para ti.

Diseño de extremo a extremo

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

factorial(really_big_number, what_to_do_with_the_result)

El segundo parámetro, what_to_do_with_the_result, es una función que envías a factorial, con la esperanza de que factorial lo llamará en su resultado antes de regresar.

Sí, esto significa que factorial necesita haberse escrito para admitir devoluciones de llamada.

Ahora suponga que quiere poder pasar un parámetro a su devolución de llamada. Ahora no puedes, porque no lo vas a llamar, factorial es. Asi que factorial debe escribirse para permitirle pasar sus parámetros, y solo se los entregará a su devolución de llamada cuando lo invoque. Puede verse así:

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

Ahora eso factorial permite este patrón, su devolución de llamada podría verse así:

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

y tu llamada a factorial sería

factorial(42, logIt, logger)

¿Qué pasa si quieres devolver algo de logIt? Bueno, no puedes, porque factorial no está prestando atención a eso.

Bueno, ¿por qué no? factorial solo devuelve lo que devuelve tu devolución de llamada?

Haciéndolo sin bloqueo

Dado que la ejecución debe entregarse a la devolución de llamada cuando factorial está terminado, realmente no debería devolver nada a quien llama. E idealmente, de alguna manera lanzarí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 asíncrona", lo que significa que cuando la llamas, vuelve inmediatamente pero no ha hecho realmente su trabajo todavía. Entonces necesita mecanismos para verificarlo y obtener su resultado cuando haya terminado, y su programa se ha vuelto más complejo en el proceso.

Y por cierto, usando este patrón, factorial_worker_task puede iniciar su devolución de llamada de forma asíncrona y devolver inmediatamente.

Entonces, ¿Qué haces?

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

a = f()
g(a)

y f debe llamarse de forma asíncrona, en su lugar escribirá

f(g)

dónde g se pasa como una devolución de llamada.

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

Su lenguaje de programación podría ayudarlo mucho al darle una forma de crear funciones sobre la marcha. En el código inmediatamente anterior, la función g podría ser tan pequeño como print (2*a+1). Si su lenguaje requiere que lo defina como una función separada, con un nombre y una firma completamente innecesarios, 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 una mejor forma. Entonces terminarás escribiendo algo así como

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

que es mucho más agradable.

Cómo pasar la devolución de llamada

¿Cómo pasaría la función de devolución de llamada a factorial? Bueno, puedes 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 quieras mantener un diccionario de fn name --> fn ptr en su programa, en cuyo caso podría pasar el nombre

  3. Tal vez su lenguaje le permite definir la función en el lugar, posible como un 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 está ejecutando 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 llamable por HTTP y pasar su URL.

Entiendes la idea.

El reciente aumento de las devoluciones de llamada

En esta era de la web en la que hemos ingresado, los servicios que invocamos suelen estar en 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 activos o de que funcionen.

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

JavaScript admite devoluciones de llamada muy bien, p. con lambdas y cierres. Y hay mucha actividad en el mundo de JavaScript, tanto en el navegador como en el servidor. Incluso hay plataformas de JavaScript desarrolladas para dispositivos móviles.

A medida que avanzamos, cada vez más de nosotros escribiremos código asíncrono, para lo cual esta comprensión será esencial.


176
2018-05-04 06:34



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

La página de devolución 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 una parte del código ejecutable, que se pasa como un 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.


87
2018-05-05 10:19



Una respuesta de lego sería que no es una función suya sino del usuario o del navegador después de que se ha producido un determinado evento o después de que se haya procesado algún código.


40
2017-09-15 16:48



Una función de devolución de llamada es aquella a la que se debe llamar cuando se cumple una determinada condición. En lugar de llamarse de inmediato, se llama a la función de devolución de llamada en un cierto punto en el futuro.

Por lo general, se usa cuando se inicia una tarea que terminará 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 su interlocutor proporcione una función de devolución de llamada que se invocará cuando la página web haya terminado de descargarse.


37
2018-05-05 16:07



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

Una función de devolución de llamada es una función que le pasa a alguien y deja   ellos lo llaman en algún momento del tiempo.

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

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

He estado trabajando con muchas API, veo varios ejemplos malos. Muchas personas tienden a nombrar un puntero a la función (una referencia al código ejecutable) o funciones anónimas (un fragmento 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 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.

entonces la diferencia es a quién le va a pasar la función y cómo se va a llamar a su función de transferencia. Si solo define una función y la pasa a otra función y la llama directamente en ese cuerpo de función, no la llame de devolución de llamada. La definición dice que su función de transferencia 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 comprender mejor solo peor.


34
2017-07-20 10:58



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

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


26
2018-01-11 01:13



Vamos a mantenerlo 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 ella ha hecho eso, hacer: (ii) cualquier tarea que le escribí en uno de esos notas adhesivas.

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

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

En resumen:

  1. primero, ella necesita dejar el correo y
  2. inmediatamente despues eso está hecho, 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 el correo se dejó, y también porque la nota adhesiva diciéndole a imprimir el documento se da a ella junto con el correo que necesita más.

Vamos a vincular 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.
  • Así que "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 aclare, y si no, publique un comentario y haré todo lo posible para aclararlo.


21
2018-02-29 12:26



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

No estoy seguro de que eso es lo que son.

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 tienen el propósito de hacer frente a la invocación de origen, en una especie de "bueno eso lo que pidió que lo he hecho -!? simplemente pensaba que iba a hacerle saber - volver a usted".


16
2017-10-27 23:18