Perché abbiamo bisogno di "funzioni di richiamata"?


16

Sto leggendo il libro programming in Lua. Detto questo

Le chiusure forniscono uno strumento prezioso in molti contesti. Come abbiamo visto, sono utili come argomenti per funzioni di ordine superiore come l'ordinamento. Le chiusure sono utili per le funzioni che creano anche altre funzioni, come il nostro esempio newCounter; questo meccanismo consente ai programmi Lua di incorporare sofisticate tecniche di programmazione dal mondo funzionale. Le chiusure sono utili anche per le funzioni di callback. Un esempio tipico qui si verifica quando si creano pulsanti in un toolkit GUI convenzionale. Ogni pulsante ha una funzione di richiamata da chiamare quando l'utente preme il pulsante; vuoi che pulsanti diversi facciano cose leggermente diverse quando vengono premuti. Ad esempio, una calcolatrice digitale necessita di dieci pulsanti simili, uno per ogni cifra. Puoi crearli ciascuno con una funzione come questa:

function digitButton (digit)
  return Button{label = tostring(digit),
                action = function ()
                  add_to_display(digit)
                  end}
end

Sembra che se chiamo il digitButton, restituirà il action(questo creerà una chiusura), quindi posso accedere al digitpassato digitButton.

La mia domanda è che:

Why we need call back functions? what situations can I apply this to?


L'autore ha detto:

In questo esempio, supponiamo che Button sia una funzione di toolkit che crea nuovi pulsanti; l'etichetta è l'etichetta del pulsante; e action è la chiusura del callback da chiamare quando si preme il pulsante. Il callback può essere chiamato molto tempo dopo che digitButton ha svolto il suo compito e dopo che la cifra della variabile locale è uscita dall'ambito, ma può comunque accedere a questa variabile.

secondo l'autore, penso che un esempio simile sia questo:

function Button(t)
  -- maybe you should set the button here
  return t.action -- so that you can call this later
end

function add_to_display(digit)
  print ("Display the button label: " .. tostring(digit))
end

function digitButton(digit)
  return Button{label = tostring(digit),
                action = function ()
                           add_to_display(digit)
                           end}
end

click_action = digitButton(10)
click_action()

in tal modo, the callback can be called a long time after digitButton did its task and after the local variable digit went out of scope.


Risposte:


45

Da Guy 1 a Guy 2: hey amico Voglio fare qualcosa quando un utente fa clic lì, richiamami quando succede, va bene?

Guy 2 richiama Guy 1 quando un utente fa clic qui.


1
Mi piace molto questa battuta di richiamata :-P
Lucas Li,

6
Sono solo io? Non capisco come questo spieghi perché abbiamo bisogno delle funzioni di callback.
phant0m

2
È più come Guy 1 dice a Guy 2 "quando è il momento di farlo". Guy 2 racconta la sua giornata e quando è il momento giusto lo fa. Se intendevi che Guy 1 fosse il chiamante di Guy 2, allora questo non è corretto in quanto Guy 2 non richiama Guy 1, chiama la cosa da fare. In effetti, se Guy 1 è il chiamante di Guy 2, avresti un giro duro in questo scenario. Se intendevi Guy 1 come callback, allora questo è errato poiché il callback non ha idea di chi sia Guy 2 e certamente non gli chiede di chiamare.
rism

Questa è una spiegazione orribile.
insidesin

21

No, non restituirà mai l'azione. Il pulsante lo eseguirà quando l'utente farà clic su di esso. E questa è la risposta. Hai bisogno di funzioni di callback quando vuoi definire azioni che dovrebbero accadere in un altro componente in reazione a un evento che non controlli (il loop di eventi, che fa parte del sistema, eseguirà un metodo del pulsante che a sua volta verrà eseguito l'azione).


Non sono d'accordo con te Ho modificato il mio post e ho aggiunto alcuni codici. Penso ancora che l'azione non venga eseguita all'istante.
Lucas Li,

2
Tim, hai ragione, ma lo è anche Jan. "Il pulsante lo eseguirà quando l'utente fa clic su di esso", non istantaneamente.
AlexanderBrevig,

@AlexanderBrevig sì, penso ancora che la risposta di Jan sia molto utile per me. Mi fa sapere cosa è la richiamata e perché dobbiamo richiamare.
Lucas Li,

Il callback è solo un nome sporco che qualcuno ha aggiunto a una seconda funzione che funziona quando viene attivato il primo e forse basato su un criterio. Chiama la tua funzione well_done () e non farebbe differenza. Callback è come verificare, verificare è una sequenza di messaggi, di solito due, e callback è una sicurezza di funzioni, di solito due. Se hai incatenato più di 3 callback, congratulazioni, ti piace fare le cose nel modo più duro.
m3nda,

16

Penso che un esempio migliore per l'uso dei callback sia nelle funzioni asincrone. Non posso parlare per Lua, ma in JavaScript, una delle azioni asincrone più comuni è contattare un server tramite AJAX.

La chiamata AJAX è asincrona, il che significa che se fai qualcosa del genere:

var ajax = ajaxCall();
if(ajax == true) {
  // Do something
}

il contenuto del ifblocco non verrà eseguito correttamente in modo affidabile e, in tal caso, è solo perché la ajaxCall()funzione è terminata prima che l'esecuzione raggiungesse l' ifistruzione.

Tuttavia, i callback eliminano questo problema, assicurandosi che la chiamata asincrona sia terminata prima di chiamare la funzione richiesta. Quindi, il tuo codice cambierebbe in qualcosa del genere:

function ajaxCallback(response) {   
  if(response == true) {
    // Do something   
  }
}

ajaxCall(ajaxCallback);

Lo scopo è quello di consentirti di fare cose come raccogliere dati, senza interferire con altre cose, come disegnare l'interfaccia. Se la raccolta dei dati fosse sincrona, l'interfaccia non risponderebbe mentre l'applicazione attendeva di ottenere i dati. Un'interfaccia che non risponde è molto negativa per l'esperienza dell'utente, poiché la maggior parte degli utenti penserà che l'applicazione si sia "bloccata" e proverà a terminare il processo.

Per vederlo in azione, devi solo guardare qualsiasi sito Web che esegue qualsiasi tipo di aggiornamento senza ricaricare l'intera pagina. Twitter, LinkedIn e i siti StackExchange sono buoni esempi. Lo "scorrimento continuo" di feed di Twitter e le notifiche di SE (sia per le notifiche degli utenti, sia per le notifiche che una domanda ha una nuova attività), sono alimentati da chiamate asincrone. Quando vedi uno spinner da qualche parte, significa che quella sezione ha effettuato una chiamata asincrona e attende che la chiamata finisca, ma puoi interagire con altre cose sull'interfaccia (e persino effettuare altre chiamate asincrone). Al termine della chiamata, reagirà e aggiornerà di conseguenza l'interfaccia.


12

Hai fatto la domanda

Perché abbiamo bisogno di "funzioni di richiamata"?

Cercherò di rispondere in modo conciso e chiaro (se non ci riesco, fai riferimento al link wiki in fondo a questa risposta).

I callback sono usati per rinviare l'implementazione specifica di qualcosa all'ultimo momento possibile.

L'esempio del pulsante ne è una buona illustrazione. Supponiamo che tu voglia avere un pulsante nella tua applicazione che stampa una pagina sulla stampante, potremmo immaginare un mondo in cui dovresti codificare un'intera nuova PrinterButtonclasse per farlo.

Fortunatamente, abbiamo la nozione di callback (l'ereditarietà e l'uso del modello di template è anche una sorta di callback semantico) quindi non abbiamo bisogno di farlo.

Invece di reimplementare ogni aspetto di un pulsante, ciò che facciamo è aggiungere all'implementazione del pulsante. L' Buttonha il concetto di fare qualcosa quando viene premuto. Diciamo semplicemente che cos'è quel qualcosa.

Quel meccanismo di iniezione del comportamento nei framework è chiamato callbacks.

Esempio:

Iniettiamo un comportamento in un pulsante HTML:

<button onclick="print()">Print page through a callback to the print() method</button>

In questo caso, onclickpunta a un callback, che per questo esempio è il print()metodo.


http://en.wikipedia.org/wiki/Callback_(computer_programming)


Grazie, dopo aver letto la tua illustrazione, vado a leggere il wiki i cui esempi sono solo callback sincroni.
Lucas Li,

dire a una funzione la risposta ogni volta che ha un problema e bisogna ascoltarlo; insegnare una funzione per risolvere un problema che si prende cura di se stesso.
Joe,

8

Perché abbiamo bisogno di funzioni di richiamata? a quali situazioni posso applicarlo?

Le funzioni di callback sono molto utili nella programmazione guidata dagli eventi. Ti consentono di impostare il tuo programma in modo tale che gli eventi attivino il codice corretto. Questo è molto comune nei programmi con GUI in cui gli utenti possono fare clic su qualsiasi elemento dell'interfaccia utente (come pulsanti o voci di menu) e verrà eseguito il codice appropriato.


1
+ Ecco a cosa servono i callback, ma odio doverli scrivere :-)
Mike Dunlavey,

Quando ero solo una matricola, il mio insegnante ci ha insegnato a programmare in MFC, ma non ci ha mai detto cosa è il callback :-(
Lucas Li

2

Cosa succede senza richiamate:

Guy 1: Okay, sto aspettando che accada quella cosa. (fischi, twiddles pollici)

Guy 2: Dannazione! Perché Guy 1 non mi sta mostrando cose? Voglio vedere cose accadere !! Dov'è la mia roba? Come si può fare qualcuno qui?


1

Prima di tutto, il termine callback si riferisce a una chiusura che viene utilizzata per qualcosa.

Ad esempio, supponiamo di creare una funzione di chiusura e di memorizzarla in una variabile. Non è un callback, perché non viene utilizzato per nulla.

Supponiamo che tu crei una chiusura e la memorizzi da qualche parte che verrà chiamata quando succede qualcosa. Ora è definito un callback.

Di solito, i callback vengono creati da parti diverse del programma rispetto alle parti che li chiamano. Quindi è facile immaginare che alcune parti del programma stiano "richiamando" le altre parti.

In poche parole, i callback consentono a una parte del programma di dire a un'altra parte di fare qualcosa (qualsiasi cosa) quando succede qualcosa.

Per quanto riguarda le variabili mantenute in vita a causa dell'utilizzo in una chiusura, questa è una funzione completamente diversa chiamata upvalues ​​(ovvero "estendere la durata delle variabili locali" tra coloro che non parlano Lua). Ed è anche abbastanza utile.


sì, Extending the lifetime of local variablesè anche per dire il termine upvalue.
Lucas Li,

Mmm, interessante. Il termine upvalue sembra essere specifico di Lua, sebbene una rapida ricerca su Google dimostri che è stato usato occasionalmente per descrivere altre lingue. Lo aggiungerò alla mia risposta.
Jonathan Graef,

1

I callback sono in circolazione sin dai primi giorni di Fortran, almeno. Ad esempio, se si dispone di un solutore ODE (equazione differenziale ordinaria), come un solutore Runge-Kutta, potrebbe apparire così:

subroutine rungekutta(neq, t, tend, y, deriv)
  integer neq             ! number of differential equations
  double precision t      ! initial time
  double precision tend   ! final time
  double precision y(neq) ! state vector
  ! deriv is the callback function to evaluate the state derivative
  ...
  deriv(neq, t, y, yprime) ! call deriv to get the state derivative
  ...
  deriv(neq, t, y, yprime) ! call it several times
  ...
end subroutine

Consente al chiamante di personalizzare il comportamento della subroutine passando una funzione speciale da chiamare quando necessario. Ciò consente di utilizzare il solutore ODE per simulare un'ampia varietà di sistemi.


1

Ci siamo imbattuti in questo e volevo fornire una risposta più aggiornata ...

Le funzioni di callback ci consentono di fare qualcosa con i dati in un secondo momento, consentendo l'esecuzione del resto del nostro codice, invece di aspettarlo. Il codice asincrono ci consente questo lusso di eseguire qualcosa in seguito . L'esempio più leggibile di funzioni di callback che ho incontrato sono Promesse in JavaScript. Nell'esempio seguente ogni volta che vedi la funzione (risultato) o (newResult) o (finalResult) ... queste sono funzioni di callback. Il codice tra le parentesi graffe viene eseguito una volta che i dati tornano dal server. Solo a questo punto avrebbe senso eseguire queste funzioni poiché ora sono disponibili i dati di cui hanno bisogno.

doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);

il codice è tratto da ... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Speriamo che questo aiuti qualcuno. Questo è ciò che mi ha aiutato a capire i callback :)


1
questo non sembra offrire nulla di sostanziale rispetto ai punti formulati e spiegati nelle precedenti 9 risposte
moscerino del

1
Forse per te, ma questo è ciò che mi ha reso chiari i callback, quindi ho pensato di condividere. IMO la leggibilità dell'esempio è ciò che lo rende utile. Sono sicuro che possiamo concordare che la leggibilità del codice fa molto, soprattutto per i principianti.
NRV

-2

Non conosco Lua, ma in generale i metodi di callback come il multithreading. Ad esempio, nella programmazione dello sviluppo di applicazioni mobili, la maggior parte delle applicazioni funziona come l'invio di richieste al server e la riproduzione con l'interfaccia utente con i dati forniti come risposta dal server. Quando l'utente invia una richiesta al server, ci vorrà del tempo per ottenere una risposta dal server, ma per la migliore interfaccia utente UX non dovrebbe bloccarsi.

Per questo motivo utilizziamo più thread per eseguire operazioni parallele. Quando riceviamo la risposta dal server, dobbiamo aggiornare l'interfaccia utente. dobbiamo aggiornare da quel thread per aggiornare. dal mondo funzionale. Questo tipo di chiamate di funzione sono chiamate metodi di callback. Quando chiami questi metodi, il controle dovrebbe tornare al thread principale. Ad esempio, i metodi di callback sono blocchi in obiettivo-C.


sì, quello che hai detto è coerente con la mia comprensione dopo aver letto il libro.
Lucas Li,

2
I metodi di callback non sono come il multithreading. I metodi di callback sono semplicemente puntatori a funzioni (delegati). I thread riguardano il cambio / utilizzo del contesto CPU. Un contrasto molto semplificato sarebbe che il threading riguarda l'ottimizzazione della CPU per UX mentre i callback riguardano il cambio di memoria per il polimorfismo. Il semplice fatto che i thread possano eseguire callback non significa che thread e callback siano simili. I thread eseguono anche metodi statici su classi statiche ma i tipi di thread e statici non sono simili.
rism
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.