web-dev-qa-db-fra.com

Pourquoi avons-nous besoin de "fonctions de rappel"?

Je lis le livre programming in Lua. Il a dit que

Les fermetures constituent un outil précieux dans de nombreux contextes. Comme nous l'avons vu, ils sont utiles comme arguments pour des fonctions d'ordre supérieur telles que le tri. Les fermetures sont précieuses pour les fonctions qui construisent également d'autres fonctions, comme notre exemple newCounter; ce mécanisme permet aux programmes Lua d'incorporer des techniques de programmation sophistiquées du monde fonctionnel. Les fermetures sont également utiles pour les fonctions de rappel. Un exemple typique se produit ici lorsque vous créez des boutons dans une boîte à outils GUI conventionnelle. Chaque bouton a une fonction de rappel à appeler lorsque l'utilisateur appuie sur le bouton; vous voulez que différents boutons fassent des choses légèrement différentes lorsqu'ils sont pressés. Par exemple, une calculatrice numérique a besoin de dix boutons similaires, un pour chaque chiffre. Vous pouvez créer chacun d'eux avec une fonction comme celle-ci:

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

Il semble que si j'appelle le digitButton, il renverra le action (cela créera une fermeture), donc je peux accéder au digit passé à digitButton.

Ma question est la suivante:

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

Dans cet exemple, nous supposons que Button est une fonction de boîte à outils qui crée de nouveaux boutons; label est l'étiquette du bouton; et action est la fermeture de rappel à appeler lorsque le bouton est enfoncé. Le rappel peut être appelé longtemps après que digitButton a fait sa tâche et après que la variable locale digit soit hors de portée, mais il peut toujours accéder à cette variable.

selon l'auteur, je pense qu'un exemple similaire ressemble à ceci:

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()

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

16
Lucas Li

Guy 1 à Guy 2: hé mec, je veux faire quelque chose quand un utilisateur clique dessus, rappelez-moi quand ça se passe bien?

Guy 2 rappelle Guy 1 lorsqu'un utilisateur clique ici.

45
Florian Margaine

Non, il ne sera jamais retour l'action. Le bouton exécutera lorsque l'utilisateur clique dessus. Et voilà la réponse. Vous avez besoin de fonctions de rappel lorsque vous souhaitez définir des actions qui doivent se produire dans un autre composant en réaction à un événement que vous ne contrôlez pas (la boucle d'événements, qui fait partie du système, exécutera une méthode du bouton qui à son tour s'exécutera l'action).

21
Jan Hudec

Je pense qu'un meilleur exemple pour l'utilisation des rappels est dans les fonctions asynchrones. Je ne peux pas parler pour Lua, mais en JavaScript, l'une des actions asynchrones les plus courantes consiste à contacter un serveur via AJAX.

L'appel AJAX est asynchrone, ce qui signifie que si vous faites quelque chose comme ceci:

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

le contenu du bloc if ne fonctionnera pas correctement de manière fiable, et lorsque c'est le cas, c'est uniquement parce que la fonction ajaxCall() s'est terminée avant que l'exécution n'atteigne l'instruction if.

Cependant, les rappels éliminent ce problème en garantissant que l'appel asynchrone est terminé avant d'appeler la fonction requise. Ainsi, votre code se changerait en quelque chose comme ceci:

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

ajaxCall(ajaxCallback);

Le but de ceci est de vous permettre de faire des choses comme collecter des données, sans interférer avec d'autres choses, comme dessiner l'interface. Si la collecte de données était synchrone, l'interface ne répondrait plus pendant que l'application attendait d'obtenir les données. Une interface qui ne répond pas est très mauvaise pour l'expérience utilisateur, car la plupart des utilisateurs penseront que l'application a "planté" et essaieront de terminer le processus.

Pour voir cela en action, il vous suffit de consulter n'importe quel site Web qui effectue n'importe quel type de mise à jour sans recharger la page entière. Twitter, LinkedIn et les sites StackExchange en sont de bons exemples. Le "défilement sans fin" des flux de Twitter et les notifications de SE (pour les notifications des utilisateurs et les notifications qu'une question a une nouvelle activité) sont alimentés par des appels asynchrones. Lorsque vous voyez un spinner quelque part, cela signifie que la section a effectué un appel asynchrone et attend que cet appel se termine, mais vous pouvez interagir avec d'autres choses sur l'interface (et même effectuer d'autres appels asynchrones). Une fois cet appel terminé, il réagira et mettra à jour l'interface en conséquence.

16
Shauna

Vous avez posé la question

Pourquoi avons-nous besoin de "fonctions de rappel"?

J'essaierai d'y répondre de manière concise et claire (si j'échoue à cela, veuillez vous référer au lien wiki au bas de cette réponse).

Les rappels sont utilisés pour reporter l'implémentation spécifique de quelque chose au dernier moment possible.

L'exemple de bouton en est une bonne illustration. Supposons que vous vouliez avoir un bouton dans votre application qui imprime une page sur l'imprimante, nous pourrions imaginer un monde où vous auriez à coder une toute nouvelle classe PrinterButton pour ce faire.

Heureusement, nous avons la notion de callbacks (l'héritage et l'utilisation du modèle de modèle est aussi une sorte de sémantique de callback) donc nous n'avons pas besoin de faire ça.

Au lieu de réimplémenter chaque aspect d'un bouton, ce que nous faisons est d'ajouter à l'implémentation du bouton. Le Button a le concept de faire quelque chose quand il est pressé. Nous lui disons simplement ce qu'est ce quelque chose.

Ce mécanisme d'injection de comportement dans les frameworks est appelé callbacks.

Exemple:

Injectons un certain comportement dans un bouton HTML:

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

Dans ce cas, onclick pointe vers un rappel, qui pour cet exemple est la méthode print().


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

12
AlexanderBrevig

Pourquoi avons-nous besoin de fonctions de rappel? à quelles situations puis-je l'appliquer?

Les fonctions de rappel sont très utiles dans la programmation événementielle. Ils vous permettent de configurer votre programme de telle manière que les événements déclenchent le code correct. Ceci est très courant dans les programmes avec GUI où les utilisateurs peuvent cliquer sur n'importe quel élément de l'interface utilisateur (tels que les boutons ou les éléments de menu) et le code approprié sera exécuté.

Que se passe-t-il sans rappels:

Guy 1: D'accord, j'attends que cette chose arrive. (sifflets, pouces twiddles)

Guy 2: Bon sang! Pourquoi Guy 1 ne me montre-t-il pas des trucs? Je veux voir des choses se passer !! Où est mon équipement? Comment peut-on faire quoi que ce soit ici?

2
Jim

Je suis tombé sur cela et je voulais apporter une réponse plus à jour ...

Les fonctions de rappel nous permettent de faire quelque chose avec les données à un moment plus tard , permettant au reste de notre code de s'exécuter, au lieu de l'attendre. Le code asynchrone nous permet ce luxe d'exécuter quoi que ce soit plus tard . L'exemple le plus lisible de fonctions de rappel que j'ai rencontré est Promises in JavaScript. Dans l'exemple ci-dessous chaque fois que vous voyez la fonction (result) ou (newResult) ou (finalResult) ... ce sont des fonctions de rappel. Le code entre crochets est exécuté une fois que les données reviennent du serveur. Ce n'est qu'à ce stade qu'il serait logique d'exécuter ces fonctions, car maintenant les données dont elles ont besoin sont disponibles.

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

le code est extrait de ... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Espérons que cela aide quelqu'un. C'est ce qui m'a aidé à comprendre les rappels :)

1
NRV

Tout d'abord, le terme rappel fait référence à une fermeture qui est utilisée pour quelque chose.

Par exemple, supposons que vous créez une fonction de fermeture et que vous la stockiez simplement dans une variable. Ce n'est pas un rappel, car il n'est utilisé pour rien.

Mais supposons que vous créiez une fermeture et la stockiez quelque part où elle sera appelée quand quelque chose se passera. Il est maintenant appelé un rappel.

Habituellement, les rappels sont créés par différentes parties du programme que les parties qui les appellent. Il est donc facile d'imaginer que certaines parties du programme "rappellent" les autres parties.

Autrement dit, les rappels permettent à une partie du programme de dire à une autre partie de faire quelque chose (n'importe quoi) quand quelque chose se passe.

Quant aux variables maintenues en vie en raison de leur utilisation dans une fermeture, c'est une caractéristique complètement différente appelée upvalues ​​(alias "prolonger la durée de vie des variables locales" parmi ceux qui ne parlent pas Lua). Et c'est aussi très utile.

1
Jonathan Graef

Les rappels existent depuis les premiers jours de Fortran, au moins. Par exemple, si vous avez un solveur ODE (équation différentielle ordinaire), tel qu'un solveur Runge-Kutta, il pourrait ressembler à ceci:

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

Il permet à l'appelant de personnaliser le comportement du sous-programme en lui passant une fonction spéciale à appeler si nécessaire. Cela permet au solveur ODE d'être utilisé pour simuler une grande variété de systèmes.

1
Mike Dunlavey