Was ist eine Rückruffunktion?


684

Was ist eine Rückruffunktion?


8
Sie finden hier: stackoverflow.com/a/9652434/3343174 die beste Erklärung für Rückrufe
Fakher


Schauen Sie sich die zweite Antwort für eine detaillierte Erklärung an
Donato

Die beste Erklärung für einen Rückruf, die ich jemals gefunden habe youtube.com/watch?v=xHneyv38Jro
Sameer Sinha

Antworten:


680

Entwickler sind oft verwirrt darüber, was ein Rückruf aufgrund des Namens der verdammten Sache ist.

Eine Rückruffunktion ist eine Funktion, die:

  • zugänglich durch eine andere Funktion, und
  • wird nach der ersten Funktion aufgerufen, wenn diese erste Funktion abgeschlossen ist

Eine gute Möglichkeit, sich vorzustellen, wie eine Rückruffunktion funktioniert, besteht darin, dass es sich um eine Funktion handelt, die " auf der Rückseite " der Funktion aufgerufen wird, an die sie übergeben wird.

Vielleicht wäre ein besserer Name eine "Call After" -Funktion.

Dieses Konstrukt ist sehr nützlich für asynchrones Verhalten, bei dem eine Aktivität immer dann stattfinden soll, wenn ein vorheriges Ereignis abgeschlossen ist.

Pseudocode:

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

Ergebnis, wenn Sie event () aufgerufen haben:

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

Die Reihenfolge der Ausgabe ist hier wichtig. Da die Rückruffunktionen anschließend aufgerufen werden, wird "Ich habe das Drucken von Nummern beendet" zuletzt und nicht zuerst gedruckt.

Rückrufe werden aufgrund ihrer Verwendung mit Zeigersprachen so genannt. Wenn Sie keine davon verwenden, arbeiten Sie nicht über den Namen "Rückruf". Verstehen Sie einfach, dass es nur ein Name ist, um eine Methode zu beschreiben, die als Argument für eine andere Methode angegeben wird, z. Die Rückruffunktion wird dann aufgerufen.

Einige Sprachen unterstützen Konstrukte, bei denen mehrere Rückruffunktionsargumente unterstützt werden, und werden basierend auf dem Abschluss der übergeordneten Funktion aufgerufen (dh ein Rückruf wird aufgerufen, wenn die übergeordnete Funktion erfolgreich abgeschlossen wurde, ein anderer wird aufgerufen, wenn die übergeordnete Funktion a auslöst spezifischer Fehler usw.).


31
Ihr Beispiel ist großartig, aber ich verstehe nicht, warum die Terminologie "Rückruf" ist. Wann wird meanOfLife "zurückgerufen"?
CodyBugstein

4
Hallo, ungefähr once its parent method completes, the function which this argument represents is then called. Wenn also die Funktion als Argument an eine andere Funktion übergeben wird, aber wie in der Mitte der Laufzeit der übergeordneten Funktion aufgerufen wird parent(cb) {dostuff1(); cb(); dostuff2()}, wird sie nicht als callbackFunktion betrachtet?
Max Yari

2
@MaxYari: IMHO, es wird immer noch als Rückruf betrachtet. Wichtig ist hier, dass die übergeordnete Funktion die Eingabefunktion (auch als Rückruf bezeichnet) irgendwie verwendet. Es kann in der Mitte oder am Ende aufgerufen werden oder wenn eine Bedingung erfüllt ist.
Kamran Bigdely

12
@ 8bitjunkie Danke - aber wo wird die Methode "Meaning of Life" in der Funktion "printANumber" aufgerufen?
BKSpurgeon

2
Dies ist überhaupt nicht wahr: "wird nach Abschluss dieser ersten Funktion automatisch aufgerufen". Ein Rückruf muss überhaupt nicht ausgeführt werden, geschweige denn automatisch. Tatsächlich ist es nicht ungewöhnlich, dass Rückrufe abgeschlossen werden, bevor die übergeordnete Funktion abgeschlossen ist. Ich mag es nicht, wie Leute Rückrufe als Funktionen beschreiben, die "später" ausgeführt werden. Es ist sehr verwirrend für Leute, die etwas über sie lernen. Einfach ausgedrückt sind Rückrufe nur Funktionen, die als Argumente an andere Funktionen übergeben werden. Zeitraum. Eine bessere Erklärung wäre die Erklärung von WARUM-Rückrufen über Funktionsreferenzen.
Jordanien

224

Undurchsichtige Definition

Eine Rückruffunktion ist eine Funktion, die Sie einem anderen Code bereitstellen, damit dieser von diesem Code aufgerufen werden kann.

Erfundenes Beispiel

Warum willst du das tun? Angenommen, Sie müssen einen Dienst aufrufen. Wenn der Service sofort zurückkehrt, müssen Sie nur:

  1. Nennen
  2. Warten Sie auf das Ergebnis
  3. Fahren Sie fort, sobald das Ergebnis eingeht

Angenommen, der Dienst wäre die factorialFunktion. Wenn Sie den Wert von möchten 5!, würden Sie aufrufen factorial(5)und die folgenden Schritte würden ausgeführt:

  1. Ihr aktueller Ausführungsort wird gespeichert (auf dem Stapel, aber das ist nicht wichtig)

  2. Die Ausführung wird an übergeben factorial

  3. Wenn factorialder Vorgang abgeschlossen ist, wird das Ergebnis an einer Stelle abgelegt, an der Sie es erreichen können

  4. Die Ausführung kehrt dorthin zurück, wo sie in [1] war.

Nehmen wir nun an, es factorialhat sehr lange gedauert, weil Sie ihm riesige Zahlen geben und es irgendwo auf einem Supercomputer-Cluster laufen muss. Angenommen, Sie erwarten, dass es 5 Minuten dauert, bis Ihr Ergebnis zurückgegeben wird. Du könntest:

  1. Behalten Sie Ihr Design bei und führen Sie Ihr Programm nachts aus, wenn Sie schlafen, damit Sie nicht die halbe Zeit auf den Bildschirm starren

  2. Entwerfen Sie Ihr Programm, um andere Dinge zu tun, während factoriales seine Sache tut

Wenn Sie die zweite Option auswählen, funktionieren Rückrufe möglicherweise für Sie.

End-to-End-Design

Um ein Rückrufmuster auszunutzen, möchten Sie in der Lage sein, factorialauf folgende Weise aufzurufen :

factorial(really_big_number, what_to_do_with_the_result)

Der zweite Parameter what_to_do_with_the_resultist eine Funktion, an die Sie senden factorial, in der Hoffnung, dass factorialsie das Ergebnis vor der Rückkehr aufruft.

Ja, das bedeutet das factorial geschrieben werden muss, um Rückrufe zu unterstützen.

Angenommen, Sie möchten einen Parameter an Ihren Rückruf übergeben können. Jetzt können Sie nicht, weil Sie es nicht nennen werden, factorialist. Es factorialmuss also geschrieben werden, damit Sie Ihre Parameter übergeben können, und sie werden nur an Ihren Rückruf übergeben, wenn dieser aufgerufen wird. Es könnte so aussehen:

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

Nun, da factorialdieses Muster zulässig ist, könnte Ihr Rückruf folgendermaßen aussehen:

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

und dein Anruf factorialwäre

factorial(42, logIt, logger)

Was ist, wenn Sie etwas zurückgeben möchten logIt? Das kannst du nicht, weilfactorial nicht darauf achtest.

Warum nicht? factorial einfach zurückgeben, was Ihr Rückruf zurückgibt?

Machen Sie es nicht blockierend

Da die Ausführung nach Abschluss an den Rückruf übergeben werden factorialsoll, sollte sie dem Anrufer eigentlich nichts zurückgeben. Und im Idealfall würde es irgendwie seine Arbeit in einem anderen Thread / Prozess / Maschine starten und sofort zurückkehren, damit Sie fortfahren können, vielleicht so etwas:

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

Dies ist jetzt ein "asynchroner Aufruf". Wenn Sie ihn aufrufen, wird er sofort zurückgegeben, hat seine Aufgabe jedoch noch nicht wirklich erledigt. Sie benötigen also Mechanismen, um dies zu überprüfen und das Ergebnis zu erhalten, wenn es fertig ist, und Ihr Programm ist dabei komplexer geworden.

Übrigens mit diesem Muster die factorial_worker_task können Sie Ihren Rückruf asynchron starten und sofort zurückkehren.

Also, was machst du?

Die Antwort ist, innerhalb des Rückrufmusters zu bleiben. Wann immer du schreiben willst

a = f()
g(a)

und fsoll asynchron aufgerufen werden, schreiben Sie stattdessen

f(g)

wo gwird als Rückruf übergeben.

Dies ändert die Flusstopologie Ihres Programms grundlegend und ist gewöhnungsbedürftig.

Ihre Programmiersprache kann Ihnen sehr helfen, indem sie Ihnen die Möglichkeit gibt, Funktionen im laufenden Betrieb zu erstellen. Im Code direkt darüber ist die Funktion gmöglicherweise so klein wie print (2*a+1). Wenn Ihre Sprache erfordert, dass Sie dies als separate Funktion mit einem völlig unnötigen Namen und einer völlig unnötigen Signatur definieren, wird Ihr Leben unangenehm, wenn Sie dieses Muster häufig verwenden.

Wenn Sie andererseits mit Ihrer Sprache Lambdas erstellen können, sind Sie in einer viel besseren Verfassung. Sie werden dann am Ende so etwas schreiben

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

das ist so viel schöner.

So leiten Sie den Rückruf weiter

Wie würden Sie die Rückruffunktion übergeben factorial? Nun, Sie können es auf verschiedene Arten tun.

  1. Wenn die aufgerufene Funktion im selben Prozess ausgeführt wird, können Sie einen Funktionszeiger übergeben

  2. Oder vielleicht möchten Sie ein Wörterbuch von fn name --> fn ptrin Ihrem Programm pflegen. In diesem Fall könnten Sie den Namen übergeben

  3. Vielleicht erlaubt Ihnen Ihre Sprache, die Funktion direkt zu definieren, möglich als Lambda! Intern wird eine Art Objekt erstellt und ein Zeiger übergeben, aber darüber müssen Sie sich keine Sorgen machen.

  4. Möglicherweise wird die von Ihnen aufgerufene Funktion auf einem völlig separaten Computer ausgeführt, und Sie rufen sie über ein Netzwerkprotokoll wie HTTP auf. Sie können Ihren Rückruf als HTTP-aufrufbare Funktion verfügbar machen und seine URL übergeben.

Du hast die Idee.

Der jüngste Anstieg von Rückrufen

In dieser Web-Ära, in die wir eingetreten sind, werden die von uns aufgerufenen Dienste häufig über das Netzwerk bereitgestellt. Wir haben oft keine Kontrolle über diese Dienste, dh wir haben sie nicht geschrieben, wir pflegen sie nicht, wir können nicht sicherstellen, dass sie verfügbar sind oder wie sie funktionieren.

Wir können jedoch nicht erwarten, dass unsere Programme blockiert werden, während wir darauf warten, dass diese Dienste antworten. In diesem Bewusstsein entwerfen die Dienstanbieter häufig APIs nach dem Rückrufmuster.

JavaScript unterstützt Rückrufe sehr gut, zB bei Lambdas und Closures. In der JavaScript-Welt gibt es viele Aktivitäten, sowohl im Browser als auch auf dem Server. Es werden sogar JavaScript-Plattformen für Mobilgeräte entwickelt.

Im weiteren Verlauf werden immer mehr von uns asynchronen Code schreiben, für den dieses Verständnis von entscheidender Bedeutung sein wird.


1
Ein Konzept sehr gut erklärt ..! :)
piyushGoyal

Tolle Erklärung, +1.
Lingamurthy CS

1
Dies ist die beste Antwort unter allen anderen. Bitte stimmen Sie es ab.
Abhishek Nalin

3
Perfekt erklärt und alles erklärt. Ich wünschte, ich könnte es wieder verbessern.
Yogesh Yadav

Ja, ich verstehe, wie Lambas in Javascript und Ruby funktionieren. Und Java 8, aber alte Versionen von Java verwendeten keine Lambas und stattdessen Klassen, und ich würde gerne wissen, wie diese Art von Rückruf funktioniert. Immer noch eine überlegene Antwort auf die andere.
Donato

96

Beachten Sie, dass Rückruf ein Wort ist.

Die Wikipedia-Rückrufseite erklärt es sehr gut.

Zitat aus der Wikipedia-Seite:

Bei der Computerprogrammierung ist ein Rückruf eine Referenz auf ausführbaren Code oder einen ausführbaren Code, der als Argument an anderen Code übergeben wird. Auf diese Weise kann eine untergeordnete Softwareschicht eine Unterroutine (oder Funktion) aufrufen, die in einer übergeordneten Ebene definiert ist.


14
Gute Möglichkeit, eine Antwort zu präsentieren.
Chathuranga Chandrasekara

1
Und das führt auch auf andere Weise zur Antwort. Das Substantiv "Rückruf" ist das, was "zurückgerufen" wurde, genauso wie etwas, das heruntergefahren wurde, heruntergefahren wurde und etwas, das zum Anmelden verwendet wird, ein Login ist.
Anonym

22
Dies könnte ein Kommentar gewesen sein - im Grunde ist es ein Link zu Wikipedia
CodyBugstein

Wikipedia hat tatsächlich einige wirklich großartige Programmiermaterialien in seinen Schätzen. Ich hatte immer das Gefühl, dass der Begriff "Rückruf" am besten mit dem Satz "Ich rufe zurück zu ..." erklärt wird
Thomas

Tolle Erklärung unter javascriptissexy.com/…; was ich hier neu posten werde; Eine Rückruffunktion ist eine Funktion, die als Parameter an eine andere Funktion übergeben wird, und die Rückruffunktion wird innerhalb der otherFunction aufgerufen oder ausgeführt. // Beachten Sie, dass das Element im Parameter der Klickmethode eine Funktion und keine Variable ist. // Das Element ist eine Rückruffunktion $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked") );}); Wie Sie im vorhergehenden Beispiel sehen, übergeben wir eine Funktion als Parameter an die
Klickmethode, damit

46

Eine Antwort für Laien wäre, dass es sich um eine Funktion handelt, die nicht von Ihnen, sondern vom Benutzer oder vom Browser aufgerufen wird, nachdem ein bestimmtes Ereignis eingetreten ist oder nachdem ein Code verarbeitet wurde.


42

Eine Rückruffunktion sollte aufgerufen werden, wenn eine bestimmte Bedingung erfüllt ist. Anstatt sofort aufgerufen zu werden, wird die Rückruffunktion zu einem bestimmten Zeitpunkt in der Zukunft aufgerufen.

In der Regel wird es verwendet, wenn eine Aufgabe gestartet wird, die asynchron beendet wird (dh einige Zeit nach der Rückkehr der aufrufenden Funktion beendet wird).

Für eine Funktion zum Anfordern einer Webseite muss der Aufrufer möglicherweise eine Rückruffunktion bereitstellen, die aufgerufen wird, wenn der Download der Webseite abgeschlossen ist.


In Ihrem ersten Satz sagen Sie, "...when a condition is met"aber ich dachte, Rückrufe werden aufgerufen, wenn die übergeordnete Funktion die Ausführung beendet hat und sind nicht abhängig von Bedingungen (?).
Ojonugwa Jude Ochalifu

Die "bestimmte Bedingung" bedeutet nur, dass sie im Allgemeinen aus einem bestimmten Grund und nicht zufällig angerufen werden. Ein Rückruf kann aufgerufen werden, wenn das übergeordnete Element / der Ersteller noch ausgeführt wird. Dies kann zu einer Race-Bedingung führen, wenn der Programmierer dies nicht erwartet.
Thomas Bratt

Okay. Danke für die Klarstellung
Ojonugwa Jude Ochalifu

34

Rückrufe lassen sich am einfachsten anhand des Telefonsystems beschreiben. Ein Funktionsaufruf ist analog dazu, jemanden am Telefon anzurufen, ihr eine Frage zu stellen, eine Antwort zu erhalten und aufzulegen. Durch Hinzufügen eines Rückrufs wird die Analogie geändert, sodass Sie ihr nach dem Stellen einer Frage auch Ihren Namen und Ihre Nummer geben, damit sie Sie mit der Antwort zurückrufen kann.

- Paul Jakubik, "Callback-Implementierungen in C ++"


1
Mein Name und meine Nummer sind also eine Funktion?
Koray Tugay

Nein, das wäre die Analogie, wenn "Rückruf" ein guter Name für das wäre, was stattdessen ist: Sie bitten den Telefonisten, einen Anruf zu tätigen. Das Ende.
Gherson

33

Ich glaube, dieser "Rückruf" -Jargon wurde an vielen Stellen fälschlicherweise verwendet. Meine Definition wäre so etwas wie:

Eine Rückruffunktion ist eine Funktion, die Sie an jemanden übergeben und ihn zu einem bestimmten Zeitpunkt aufrufen lassen.

Ich denke, die Leute lesen gerade den ersten Satz der Wiki-Definition:

Ein Rückruf ist eine Referenz auf ausführbaren Code oder einen ausführbaren Code, der als Argument an anderen Code übergeben wird.

Ich habe mit vielen APIs gearbeitet, siehe verschiedene schlechte Beispiele. Viele Leute neigen dazu, einen Funktionszeiger (einen Verweis auf ausführbaren Code) oder anonyme Funktionen (einen Teil des ausführbaren Codes) als "Rückruf" zu bezeichnen. Wenn es sich nur um Funktionen handelt, warum benötigen Sie dafür einen anderen Namen?

Tatsächlich zeigt nur der zweite Satz in der Wiki-Definition die Unterschiede zwischen einer Rückruffunktion und einer normalen Funktion:

Dies ermöglicht einer untergeordneten Softwareschicht, eine in einer übergeordneten Ebene definierte Unterroutine (oder Funktion) aufzurufen.

Der Unterschied besteht also darin, wer die Funktion übergeben wird und wie Ihre übergebene Funktion aufgerufen wird. Wenn Sie nur eine Funktion definieren und an eine andere Funktion übergeben und direkt in diesem Funktionskörper aufrufen, nennen Sie sie keinen Rückruf. Die Definition besagt, dass Ihre übergebene Funktion von der Funktion "unterer Ebene" aufgerufen wird.

Ich hoffe, die Leute können aufhören, dieses Wort in einem mehrdeutigen Kontext zu verwenden. Es kann den Leuten nicht helfen, besser und nur schlechter zu verstehen.


2
Ihre Antwort macht Sinn ... aber ich habe Probleme, sie mir vorzustellen. Kannst du ein Beispiel geben?
CodyBugstein

3
@Zane Wong :: Im letzten haben Sie geschrieben: "Die Definition besagt, dass Ihre übergebene Funktion von der Funktion" unterer Ebene "aufgerufen wird." Können Sie bitte erklären, was die untergeordnete Funktion anzeigt? Es ist besser, wenn Sie ein Beispiel geben.
Viku

Ein Beispiel wäre schön gewesen
Yousuf Azad

1
Ich denke, der Unterschied zwischen klassischem Funktionsaufruf und Rückrufstil besteht in der Verknüpfung mit der abhängigen Richtung: Wenn Modul A von Modul B abhängt ("verwendet"), ruft A eine Funktion von B auf, ist es kein Rückruf. Wenn A einen Verweis auf seine Funktion an B übergibt, dann ruft B eine Funktion von A auf, dies ist ein Rückruf: Der Aufruf geht im Vergleich zur Modulabhängigkeit rückwärts.
XouDo

30

Lassen Sie es uns einfach halten. Was ist eine Rückruffunktion?

Beispiel durch Parabel und Analogie

Ich habe eine Sekretärin. Jeden Tag bitte ich sie: (i) die ausgehende Post der Firma bei der Post abzugeben, und nachdem sie das getan hat, Folgendes zu tun: (ii) jede Aufgabe, die ich für sie auf eine dieser Haftnotizen geschrieben habe .

Was ist nun die Aufgabe auf dem Notizzettel? Die Aufgabe variiert von Tag zu Tag.

Angenommen, an diesem Tag muss sie einige Dokumente ausdrucken. Also schreibe ich das auf die Notiz und stecke sie zusammen mit der ausgehenden Post, die sie posten muss, auf ihren Schreibtisch.

Zusammenfassend:

  1. Zuerst muss sie die Post abgeben und
  2. Unmittelbar danach muss sie einige Dokumente ausdrucken.

Die Rückruffunktion ist die zweite Aufgabe: das Ausdrucken dieser Dokumente. Weil es erledigt ist, nachdem die Post abgegeben wurde, und weil ihr die Haftnotiz, die sie zum Drucken des Dokuments auffordert, zusammen mit der Post, die sie senden muss, gegeben wird.

Lassen Sie uns dies jetzt mit dem Programmiervokabular verknüpfen

  • Der Methodenname lautet in diesem Fall: DropOffMail.
  • Die Rückruffunktion lautet: PrintOffDocuments. PrintOffDocuments ist die Rückruffunktion, da die Sekretärin dies erst tun soll, nachdem DropOffMail ausgeführt wurde.
  • Daher würde ich PrintOffDocuments als "Argument" an die DropOffMail-Methode übergeben. Dies ist ein wichtiger Punkt.

Das ist alles was es ist. Nichts mehr. Ich hoffe, das hat es für Sie geklärt - und wenn nicht, schreiben Sie einen Kommentar und ich werde mein Bestes tun, um dies zu klären.


18

Dadurch klingen Rückrufe wie return-Anweisungen am Ende von Methoden.

Ich bin mir nicht sicher, ob sie das sind.

Ich denke, Rückrufe sind tatsächlich ein Aufruf einer Funktion, als Folge einer anderen Funktion, die aufgerufen und abgeschlossen wird.

Ich denke auch, dass Rückrufe dazu gedacht sind, die ursprüngliche Anrufung in einer Art "Hey! Das Ding, nach dem Sie gefragt haben? Ich habe es getan - ich dachte nur, ich würde Sie wissen lassen - zurück zu Ihnen" zu adressieren.


1
+1 für die Befragung von Callbacks vs Return-Anweisungen. Das hat mich immer erwischt, genau wie viele Absolventen, mit denen ich zusammenarbeite.
8bitjunkie

2
Gute Antwort - hat mir geholfen, es im Gegensatz zu vielen anderen Antworten zu verstehen!
Adam

18

Was ist ein Rückruf ?

  • Im Allgemeinen wird ein Telefonanruf getätigt, um einen Anruf zurückzugeben, den jemand erhalten hat.
  • Beim Rechnen ist ein Rückruf ein ausführbarer Code, der als Argument an anderen Code übergeben wird. Wenn die Funktion mit ihrer Arbeit fertig ist (oder wenn ein Ereignis aufgetreten ist), ruft sie Ihre Rückruffunktion auf (sie ruft Sie zurück - daher der Name).

Was ist eine Rückruffunktion ?

  • Eine Rückruffunktion ist wie ein Diener, der seinen Meister "zurückruft", wenn er eine Aufgabe erledigt hat.
  • Eine Rückruffunktion ist eine Funktion, die otherFunctionals Parameter an eine andere Funktion übergeben wird (nennen wir diese andere Funktion ), und die Rückruffunktion wird innerhalb von aufgerufen (oder ausgeführt) 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

In SOA ermöglicht der Rückruf den Plugin-Modulen den Zugriff auf Dienste aus dem Container / der Umgebung.

Analogie: Rückrufe. Asynchron. Nicht blockierendes
Beispiel aus der Praxis für Rückruf


Eine Rückruffunktion ist selbst keine Funktion höherer Ordnung. Es wird an eine Funktion höherer Ordnung übergeben.
Danio

17

Call After wäre ein besserer Name als der blöde Name Callback . Wenn oder wenn eine Bedingung innerhalb einer Funktion erfüllt ist, rufen Sie eine andere Funktion auf, die Call After- Funktion, die als Argument empfangen wurde.

Anstatt eine innere Funktion innerhalb einer Funktion fest zu codieren, schreibt man eine Funktion, um eine bereits geschriebene Call After- Funktion als Argument zu akzeptieren . Der Call After wird möglicherweise basierend auf Statusänderungen aufgerufen, die vom Code in der Funktion erkannt werden, die das Argument empfängt.


Das ist eine großartige Idee. Ich habe mich für "hinten angerufen" entschieden, um dies zu erklären. Ich konnte jemanden wie Martin Fowler sehen, der "call after" als neuen Begriff für diese in seinem wegweisenden Blog populär machte.
8bitjunkie

15

Eine Rückruffunktion ist eine Funktion, die Sie für eine vorhandene Funktion / Methode angeben. Sie wird aufgerufen, wenn eine Aktion abgeschlossen ist, zusätzliche Verarbeitung erfordert usw.

In Javascript oder genauer gesagt in jQuery können Sie beispielsweise ein Rückrufargument angeben, das aufgerufen werden soll, wenn eine Animation beendet ist.

In PHP preg_replace_callback()können Sie mit dieser Funktion eine Funktion bereitstellen, die aufgerufen wird, wenn der reguläre Ausdruck übereinstimmt, und die Zeichenfolge (n) übergeben, die als Argumente übereinstimmen.


10

schau dir das Bild an :)so funktioniert es

Das Hauptprogramm ruft die Bibliotheksfunktion (möglicherweise auch eine Funktion auf Systemebene) mit dem Namen der Rückruffunktion auf. Diese Rückruffunktion kann auf mehrere Arten implementiert werden. Das Hauptprogramm wählt je nach Anforderung einen Rückruf.

Schließlich ruft die Bibliotheksfunktion die Rückruffunktion während der Ausführung auf.


7
Würde es Ihnen etwas ausmachen, dem auch eine Texterklärung hinzuzufügen ? Wenn das Bild verschwindet, verliert diese Antwort jeglichen Kontext.
Tim Post

Text von anderen Leuten erklärt es am besten. Das einzige, was mir fehlte, war das Bild :)

Von all den langwierigen Beschreibungen, die ich hier gesehen habe, hat mich diese dazu gebracht, "ahhhhh, jetzt sehe ich ihre Verwendung" zu sagen. Habe eine Gegenstimme.
DiBosco

7

Die einfache Antwort auf diese Frage lautet, dass eine Rückruffunktion eine Funktion ist, die über einen Funktionszeiger aufgerufen wird. Wenn Sie den Zeiger (die Adresse) einer Funktion als Argument an eine andere übergeben, wird beim Aufrufen der Funktion, auf die dieser Zeiger verweist, darauf hingewiesen, dass ein Rückruf erfolgt


6

Angenommen, wir haben eine Funktion, sort(int *arraytobesorted,void (*algorithmchosen)(void))in der ein Funktionszeiger als Argument akzeptiert werden kann, der zu einem bestimmten Zeitpunkt in sort()der Implementierung verwendet werden kann. Dann wird hier der Code, der vom Funktionszeiger adressiert algorithmchosenwird, als Rückruffunktion aufgerufen .

Und der Vorteil ist, dass wir jeden Algorithmus wählen können wie:

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

Welche wurden beispielsweise mit dem Prototyp implementiert:

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

Dies ist ein Konzept, mit dem Polymorphismus in der objektorientierten Programmierung erreicht wird


Tolle Erklärung unter javascriptissexy.com/…; was ich hier neu posten werde; Eine Rückruffunktion ist eine Funktion, die als Parameter an eine andere Funktion übergeben wird, und die Rückruffunktion wird innerhalb der otherFunction aufgerufen oder ausgeführt. // Beachten Sie, dass das Element im Parameter der Klickmethode eine Funktion und keine Variable ist. // Das Element ist eine Rückruffunktion $ ("# btn_1"). Click (function () {alert ("Btn 1 Clicked") );}); Wie Sie im vorhergehenden Beispiel sehen, übergeben wir eine Funktion als Parameter an die
Klickmethode, damit

4

„In der Computerprogrammierung ist ein Rückruf eine Referenz auf ausführbaren Code oder einen ausführbaren Code, der als Argument an anderen Code übergeben wird. Auf diese Weise kann eine untergeordnete Softwareschicht eine Unterroutine (oder Funktion) aufrufen, die in einer übergeordneten Ebene definiert ist. “ - Wikipedia

Rückruf in C mit Funktionszeiger

In C wird der Rückruf mit dem Funktionszeiger implementiert. Funktionszeiger - ist, wie der Name schon sagt, ein Zeiger auf eine Funktion.

Zum Beispiel int (* ptrFunc) ();

Hier ist ptrFunc ein Zeiger auf eine Funktion, die keine Argumente akzeptiert und eine Ganzzahl zurückgibt. Vergessen Sie NICHT, in Klammern zu setzen, sonst geht der Compiler davon aus, dass ptrFunc ein normaler Funktionsname ist, der nichts nimmt und einen Zeiger auf eine Ganzzahl zurückgibt.

Hier ist ein Code zur Demonstration des Funktionszeigers.

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

Versuchen wir nun, das Konzept des Rückrufs in C mithilfe des Funktionszeigers zu verstehen.

Das vollständige Programm enthält drei Dateien: callback.c, reg_callback.h und 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)();                               
}

Wenn wir dieses Programm ausführen, wird die Ausgabe sein

Dies ist ein Programm, das den Funktionsrückruf in register_callback in my_callback zurück im Hauptprogramm demonstriert

Die Funktion der höheren Schicht ruft eine Funktion der unteren Schicht als normalen Aufruf auf, und der Rückrufmechanismus ermöglicht es der Funktion der unteren Schicht, die Funktion der höheren Schicht über einen Zeiger auf eine Rückruffunktion aufzurufen.

Rückruf in Java über die Schnittstelle

Java hat nicht das Konzept eines Funktionszeigers. Es implementiert den Rückrufmechanismus über seinen Schnittstellenmechanismus. Hier deklarieren wir anstelle eines Funktionszeigers eine Schnittstelle mit einer Methode, die aufgerufen wird, wenn der Angerufene seine Aufgabe beendet

Lassen Sie es mich anhand eines Beispiels demonstrieren:

Die Rückrufschnittstelle

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

Der Anrufer oder die höhere Klasse

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

Die Callee oder die untere Schichtfunktion

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

Rückruf mit EventListener-Muster

  • Listenpunkt

Dieses Muster wird verwendet, um 0 bis n Anzahlen von Beobachtern / Zuhörern zu benachrichtigen, dass eine bestimmte Aufgabe beendet wurde

  • Listenpunkt

Der Unterschied zwischen dem Rückrufmechanismus und dem EventListener / Observer-Mechanismus besteht darin, dass der Angerufene beim Rückruf den einzelnen Anrufer benachrichtigt, während der Angerufene bei Eventlisener / Observer jeden benachrichtigen kann, der an diesem Ereignis interessiert ist (die Benachrichtigung kann an einige andere Teile des Anwendung, die die Aufgabe nicht ausgelöst hat)

Lassen Sie es mich anhand eines Beispiels erklären.

Die Ereignisschnittstelle

public interface Events {

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

Klassen-Widget

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

Klassenschaltfläche

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

Klassen-Kontrollkästchen

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

Aktivitätsklasse

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

Andere Klasse

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

Hauptklasse

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

Wie Sie dem obigen Code entnehmen können, haben wir eine Schnittstelle namens events, die im Grunde alle Ereignisse auflistet, die für unsere Anwendung auftreten können. Die Widget-Klasse ist die Basisklasse für alle UI-Komponenten wie Button, Checkbox. Diese UI-Komponenten sind die Objekte, die die Ereignisse tatsächlich vom Framework-Code empfangen. Die Widget-Klasse implementiert die Ereignisschnittstelle und verfügt außerdem über zwei verschachtelte Schnittstellen, nämlich OnClickEventListener und OnLongClickEventListener

Diese beiden Schnittstellen sind für das Abhören von Ereignissen verantwortlich, die auf den vom Widget abgeleiteten UI-Komponenten wie Button oder Checkbox auftreten können. Wenn wir dieses Beispiel mit dem früheren Callback-Beispiel unter Verwendung der Java-Schnittstelle vergleichen, fungieren diese beiden Schnittstellen als Callback-Schnittstelle. Der übergeordnete Code (Here Activity) implementiert diese beiden Schnittstellen. Und wenn ein Ereignis in einem Widget auftritt, wird der Code auf höherer Ebene (oder die Methode dieser Schnittstellen, die im Code auf höherer Ebene implementiert ist, der hier Aktivität ist) aufgerufen.

Lassen Sie mich nun den grundlegenden Unterschied zwischen Callback- und Eventlistener-Muster diskutieren. Wie bereits erwähnt, kann der Callee mit Callback nur einen einzigen Anrufer benachrichtigen. Im Fall eines EventListener-Musters kann sich jedoch jeder andere Teil oder jede andere Klasse der Anwendung für die Ereignisse registrieren, die auf der Schaltfläche oder dem Kontrollkästchen auftreten können. Das Beispiel für diese Art von Klasse ist die OtherClass. Wenn Sie den Code der OtherClass sehen, werden Sie feststellen, dass sie sich als Listener für das ClickEvent registriert hat, das in der in der Aktivität definierten Schaltfläche auftreten kann. Interessant ist, dass neben der Aktivität (dem Anrufer) diese andere Klasse auch benachrichtigt wird, wenn das Klickereignis auf der Schaltfläche auftritt.


Bitte vermeiden Sie nur Linkantworten . Antworten, die "kaum mehr als ein Link zu einer externen Site" sind, können gelöscht werden .
Quentin

3

Eine Rückruffunktion ist eine Funktion, die Sie (als Referenz oder Zeiger) an eine bestimmte Funktion oder ein bestimmtes Objekt übergeben. Diese Funktion oder dieses Objekt ruft diese Funktion zu einem späteren Zeitpunkt, möglicherweise mehrmals, für einen beliebigen Zweck zurück:

  • Benachrichtigen Sie das Ende einer Aufgabe
  • Anfordern eines Vergleichs zwischen zwei Elementen (wie in c qsort ())
  • Berichterstattung über den Fortschritt eines Prozesses
  • Ereignisse benachrichtigen
  • Delegieren der Instanziierung eines Objekts
  • Delegieren des Gemäldes eines Gebiets

...

Die Beschreibung eines Rückrufs als eine Funktion, die am Ende einer anderen Funktion oder Aufgabe aufgerufen wird, ist daher zu einfach (auch wenn es sich um einen häufigen Anwendungsfall handelt).


2

Ein Rückruf ist eine Idee, eine Funktion als Parameter an eine andere Funktion zu übergeben und diese nach Abschluss des Prozesses aufzurufen.

Wenn Sie das Konzept des Rückrufs durch großartige Antworten erhalten, empfehle ich Ihnen, den Hintergrund seiner Idee zu lernen.

"Warum haben sie (Informatiker) einen Rückruf entwickelt?" Möglicherweise stellen Sie ein Problem fest, das blockiert (insbesondere das Blockieren der Benutzeroberfläche). Ein Rückruf ist nicht die einzige Lösung dafür. Es gibt viele andere Lösungen (z. B. Thread, Futures, Versprechen ...).


1

Ein wichtiger Anwendungsbereich besteht darin, dass Sie eine Ihrer Funktionen als Handle (dh als Rückruf) registrieren und dann eine Nachricht senden / eine Funktion aufrufen, um Arbeiten oder Verarbeitungen durchzuführen. Nachdem die Verarbeitung abgeschlossen ist, ruft die aufgerufene Funktion unsere registrierte Funktion auf (dh der Rückruf erfolgt jetzt), was anzeigt, dass die Verarbeitung abgeschlossen ist.
Dieser Wikipedia-Link erklärt sich recht gut grafisch.


1

Eine Rückruffunktion, auch als Funktion höherer Ordnung bekannt, ist eine Funktion, die als Parameter an eine andere Funktion übergeben wird, und die Rückruffunktion wird innerhalb der übergeordneten Funktion aufgerufen (oder ausgeführt).

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

Hier haben wir eine Funktion als Parameter an die click-Methode übergeben. Und die click-Methode ruft die Rückruffunktion auf (oder führt sie aus), die wir an sie übergeben haben.


1
Eine Rückruffunktion ist selbst keine Funktion höherer Ordnung. Es wird an eine Funktion höherer Ordnung übergeben.
Danio

1

Rückruffunktion Eine Funktion, die als Argument an eine andere Funktion übergeben wurde.

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

setTimeout(test_function, 2000);

Hinweis: Im obigen Beispiel wird test_function als Argument für die Funktion setTimeout verwendet.


1
Willkommen bei Stack Overflow! Lesen Sie immer die vorhandenen Antworten, bevor Sie eine Frage beantworten. Diese Antwort wurde bereits gegeben. Anstatt die Antwort zu wiederholen, stimmen Sie die vorhandene Antwort ab. Einige Richtlinien zum Schreiben guter Antworten finden Sie hier .
dferenc
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.