Wie kann man Rückrufe in einfachem Englisch erklären? Wie unterscheiden sie sich vom Aufruf einer Funktion aus einer anderen Funktion, die einen Kontext von der aufrufenden Funktion übernimmt? Wie kann ihre Leistungsfähigkeit einem unerfahrenen Programmierer erklärt werden?
Antworten
Zu viele Anzeigen?Ich werde versuchen, dies ganz einfach zu halten. Ein "Callback" ist eine Funktion, die von einer anderen Funktion aufgerufen wird, die die erste Funktion als Parameter erhält. In den meisten Fällen ist ein "Callback" eine Funktion, die aufgerufen wird, wenn etwas geschieht. Das etwas kann in der Sprache der Programmierer als "Ereignis" bezeichnet werden.
Stellen Sie sich folgendes Szenario vor: Sie erwarten in ein paar Tagen ein Paket. Das Paket ist ein Geschenk für Ihren Nachbarn. Sobald Sie das Paket erhalten, möchten Sie es zu den Nachbarn bringen. Da Sie nicht in der Stadt sind, hinterlassen Sie Anweisungen für Ihren Ehepartner.
Du könntest ihnen sagen, sie sollen das Paket holen und es den Nachbarn bringen. Wenn Ihr Ehepartner so dumm wie ein Computer wäre, würde er an der Tür sitzen und auf das Paket warten, bis es kommt (und NICHTS ANDERES tun), und dann, sobald es da ist, würde er es zu den Nachbarn bringen. Aber es gibt einen besseren Weg. Sagen Sie Ihrem Ehepartner, dass er das Paket zu den Nachbarn bringen soll, sobald er es erhalten hat. Dann können sie ihr Leben normal weiterführen, BIS sie das Paket erhalten.
In unserem Beispiel ist der Empfang des Pakets das "Ereignis" und das Bringen des Pakets zu den Nachbarn ist der "Rückruf". Ihr Ehepartner "führt" Ihre Anweisungen, das Paket zu bringen, nur aus wenn das Paket ankommt. Viel besser!
Diese Art des Denkens ist im täglichen Leben selbstverständlich, aber Computer haben nicht die gleiche Art von gesundem Menschenverstand. Bedenken Sie, wie Programmierer normalerweise in eine Datei schreiben:
fileObject = open(file)
# now that we have WAITED for the file to open, we can write to it
fileObject.write("We are writing to the file.")
# now we can continue doing the other, totally unrelated things our program does
Hier warten wir, bis die Datei geöffnet ist, bevor wir in sie schreiben. Dadurch wird der Ausführungsfluss "blockiert", und unser Programm kann keine anderen Dinge tun, die es vielleicht tun müsste! Was wäre, wenn wir stattdessen Folgendes tun könnten?
# we pass writeToFile (A CALLBACK FUNCTION!) to the open function
fileObject = open(file, writeToFile)
# execution continues flowing -- we don't wait for the file to be opened
# ONCE the file is opened we write to it, but while we wait WE CAN DO OTHER THINGS!
Es hat sich herausgestellt, dass wir dies mit einigen Sprachen und Frameworks tun. Das ist ziemlich cool! Schau mal Node.js um diese Art des Denkens in die Praxis umzusetzen.
Oft muss eine Anwendung je nach Kontext/Zustand unterschiedliche Funktionen ausführen. Hierfür verwenden wir eine Variable, in der wir die Informationen über die aufzurufende Funktion speichern. Je nach Bedarf setzt die Anwendung diese Variable mit den Informationen über die aufzurufende Funktion und ruft die Funktion über dieselbe Variable auf.
Das Beispiel in Javascript ist unten zu sehen. Hier verwenden wir Methode Argument als Variable, wo wir Informationen über die Funktion zu speichern.
function processArray(arr, callback) {
var resultArr = new Array();
for (var i = arr.length-1; i >= 0; i--)
resultArr[i] = callback(arr[i]);
return resultArr;
}
var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]
Wie kann man Rückrufe in einfachem Englisch erklären?
Im Klartext: Eine Callback-Funktion ist wie eine Arbeiter der zu seiner Familie "zurückruft". Manager wenn er eine der folgenden Aufgaben erfüllt hat Aufgabe .
Wie unterscheiden sie sich vom Aufruf einer Funktion aus einer anderen Funktion indem sie einen Kontext von der aufrufenden Funktion übernehmen?
Es stimmt, dass Sie eine Funktion von einer anderen Funktion aus aufrufen, aber der Schlüssel ist, dass der Rückruf wie ein Objekt behandelt wird, so dass Sie die aufzurufende Funktion je nach Zustand des Systems ändern können (wie das Strategy Design Pattern).
Wie kann man ihre Leistungsfähigkeit einem unerfahrenen Programmierer erklären?
Die Leistungsfähigkeit von Callbacks lässt sich leicht an AJAX-Websites erkennen, die Daten von einem Server abrufen müssen. Das Herunterladen der neuen Daten kann einige Zeit dauern. Ohne Callbacks würde Ihre gesamte Benutzeroberfläche beim Herunterladen der neuen Daten "einfrieren", oder Sie müssten die gesamte Seite aktualisieren, anstatt nur einen Teil davon. Mit einem Callback können Sie ein "Jetzt wird geladen"-Bild einfügen und es durch die neuen Daten ersetzen, sobald diese geladen sind.
Einige Codes ohne Rückruf:
function grabAndFreeze() {
showNowLoading(true);
var jsondata = getData('http://yourserver.com/data/messages.json');
/* User Interface 'freezes' while getting data */
processData(jsondata);
showNowLoading(false);
do_other_stuff(); // not called until data fully downloaded
}
function processData(jsondata) { // do something with the data
var count = jsondata.results ? jsondata.results.length : 0;
$('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
$('#results_messages').html(jsondata.results || '(no new messages)');
}
Mit Rückruf:
Hier ist ein Beispiel mit einem Rückruf, der die jQuery-Funktion getJSON :
function processDataCB(jsondata) { // callback: update UI with results
showNowLoading(false);
var count = jsondata.results ? jsondata.results.length : 0;
$('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
$('#results_messages').html(jsondata.results || '(no new messages)');
}
function grabAndGo() { // and don't freeze
showNowLoading(true);
$('#results_messages').html(now_loading_image);
$.getJSON("http://yourserver.com/data/messages.json", processDataCB);
/* Call processDataCB when data is downloaded, no frozen User Interface! */
do_other_stuff(); // called immediately
}
Mit Verschluss:
Oft muss der Rückruf auf state
von der aufrufenden Funktion mit einer closure
die wie die Arbeiter die Informationen aus dem Manager bevor er sein Projekt abschließen kann. Aufgabe . So erstellen Sie die closure
können Sie die Funktion einbinden, damit sie die Daten im aufrufenden Kontext sieht:
/* Grab messages, chat users, etc by changing dtable. Run callback cb when done.*/
function grab(dtable, cb) {
if (null == dtable) { dtable = "messages"; }
var uiElem = "_" + dtable;
showNowLoading(true, dtable);
$('#results' + uiElem).html(now_loading_image);
$.getJSON("http://yourserver.com/user/"+dtable+".json", cb || function (jsondata) {
// Using a closure: can "see" dtable argument and uiElem variables above.
var count = jsondata.results ? jsondata.results.length : 0,
counterMsg = ['Fetched', count, 'new', dtable].join(' '),
// no new chatters/messages/etc
defaultResultsMsg = ['(no new ', dtable, ')'].join('');
showNowLoading(false, dtable);
$('#counter' + uiElem).text(counterMsg);
$('#results'+ uiElem).html(jsondata.results || defaultResultsMsg);
});
/* User Interface calls cb when data is downloaded */
do_other_stuff(); // called immediately
}
Verwendung:
// update results_chatters when chatters.json data is downloaded:
grab("chatters");
// update results_messages when messages.json data is downloaded
grab("messages");
// call myCallback(jsondata) when "history.json" data is loaded:
grab("history", myCallback);
Schließung
Zum Schluss noch eine Definition von closure
から Douglas Crockford :
Funktionen können innerhalb von anderen Funktionen definiert werden. Die innere Funktion hat Zugriff auf die Variablen und Parameter der äußeren Funktion. Wenn ein Verweis auf eine innere Funktion bestehen bleibt (z. B. als Callback-Funktion), bleiben auch die Variablen der äußeren Funktion erhalten.
Siehe auch:
Ich bin verblüfft, dass so viele intelligente Menschen nicht auf die Tatsache hinweisen, dass das Wort "Rückruf" in zweierlei Hinsicht uneinheitlich verwendet wird.
In beiden Fällen geht es um die Anpassung einer Funktion durch die Übergabe zusätzlicher Funktionalität (eine Funktionsdefinition, anonym oder benannt) an eine bestehende Funktion, d.h..
customizableFunc(customFunctionality)
Wenn die benutzerdefinierte Funktionalität einfach in den Codeblock eingefügt wird, haben Sie die Funktion wie folgt angepasst.
customizableFucn(customFunctionality) {
var data = doSomthing();
customFunctionality(data);
...
}
Obwohl diese Art von injizierter Funktionalität oft als "Rückruf" bezeichnet wird, ist daran nichts Kontingentes. Ein sehr offensichtliches Beispiel ist die forEach-Methode, bei der eine benutzerdefinierte Funktion als Argument übergeben wird, die auf jedes Element in einem Array angewendet wird, um das Array zu ändern.
Dies unterscheidet sich jedoch grundlegend von der Verwendung von "Callback"-Funktionen für asynchrone Programmierung wie in AJAX oder node.js oder einfach bei der Zuweisung von Funktionen zu Benutzerinteraktionsereignissen (wie Mausklicks). In diesem Fall geht es darum, auf das Eintreten eines bedingten Ereignisses zu warten, bevor die benutzerdefinierte Funktionalität ausgeführt wird. Dies ist bei der Benutzerinteraktion offensichtlich, aber auch bei E/A-Prozessen (Eingabe/Ausgabe) wichtig, die Zeit in Anspruch nehmen können, z. B. beim Lesen von Dateien von der Festplatte. Hier macht der Begriff "Callback" am meisten Sinn. Sobald ein E/A-Prozess gestartet wird (z. B. wenn eine Datei von der Festplatte gelesen werden soll oder ein Server Daten von einer HTTP-Anfrage zurückgibt), wird ein asynchrone Das Programm wartet nicht, bis es fertig ist. Es kann mit den nächsten geplanten Aufgaben fortfahren und erst dann mit den benutzerdefinierten Funktionen antworten, wenn es benachrichtigt wurde, dass die Lese- oder HTTP-Anforderung abgeschlossen ist (oder fehlgeschlagen ist) und die Daten für die benutzerdefinierten Funktionen verfügbar sind. Das ist so, als würde man ein Unternehmen anrufen und seine Rückrufnummer hinterlassen, damit man angerufen werden kann, wenn ein Mitarbeiter verfügbar ist, um zurückzurufen. Das ist besser, als wer weiß wie lange in der Leitung zu hängen und sich nicht um andere Dinge kümmern zu können.
Die asynchrone Verwendung beinhaltet eine Möglichkeit, auf das gewünschte Ereignis zu warten (z. B. den Abschluss des E/A-Prozesses), so dass die benutzerdefinierte "Callback"-Funktionalität ausgeführt wird, wenn es eintritt (und nur dann). Im offensichtlichen AJAX-Beispiel wird die "Callback"-Funktion ausgelöst, wenn die Daten tatsächlich vom Server ankommen, um diese Daten zu verwenden, um das DOM zu ändern und somit das Browserfenster in diesem Umfang neu zu zeichnen.
Um es kurz zu machen. Manche Leute verwenden das Wort "Rückruf" für jede Art von benutzerdefinierter Funktionalität, die als Argument in eine bestehende Funktion eingefügt werden kann. Aber, zumindest für mich, ist die angemessenste Verwendung des Wortes, wenn die eingefügte "Callback"-Funktion asynchron verwendet wird - um nur beim Auftreten eines Ereignisses ausgeführt zu werden, auf das sie wartet, um benachrichtigt zu werden.
In der Sprache der Nicht-Programmierer ist ein Callback ein Lückenfüller in einem Programm.
Ein häufiger Punkt auf vielen Papierformularen ist "Person, die im Notfall anzurufen ist". Dort gibt es eine leere Zeile. Sie tragen dort den Namen und die Telefonnummer einer Person ein. Wenn ein Notfall eintritt, wird diese Person angerufen.
- Jeder erhält dasselbe Blankoformular, aber
- Jeder kann eine andere Notfallkontaktnummer angeben.
Das ist der Schlüssel. Sie ändern nicht das Formular (den Code, der normalerweise von jemand anderem stammt). Sie können jedoch fehlende Informationen ausfüllen ( Ihr Nummer).
Beispiel 1:
Rückrufe werden als benutzerdefinierte Methoden verwendet, möglicherweise zur Ergänzung/Änderung des Verhaltens eines Programms. Nehmen wir zum Beispiel einen C-Code, der eine Funktion ausführt, aber nicht weiß, wie man eine Ausgabe macht. Alles, was er kann, ist eine Zeichenkette erstellen. Wenn er versucht, herauszufinden, was er mit der Zeichenkette machen soll, sieht er eine leere Zeile. Aber der Programmierer hat Ihnen die Leerzeile gegeben, damit Sie Ihren Rückruf hineinschreiben können!
In diesem Beispiel verwenden Sie keinen Bleistift, um ein leeres Feld auf einem Blatt Papier auszufüllen, sondern Sie verwenden die Funktion set_print_callback(the_callback)
.
- Die leere Variable in dem Modul/Code ist die leere Zeile,
set_print_callback
ist der Bleistift,- y
the_callback
ist Ihre Information, die Sie ausfüllen.
Sie haben nun diese leere Zeile im Programm ausgefüllt. Wann immer das Programm eine Ausgabe machen muss, schaut es in diese leere Zeile und folgt den Anweisungen (d.h. es ruft die Funktion auf, die Sie dort eingetragen haben). Praktisch bedeutet dies, dass Sie auf den Bildschirm, in eine Protokolldatei, auf einen Drucker, über eine Netzwerkverbindung oder eine beliebige Kombination davon drucken können. Sie haben die Leerstelle mit dem ausgefüllt, was Sie tun wollen.
Beispiel 2:
Wenn einem gesagt wird, man müsse eine Notrufnummer anrufen, geht man hin und liest, was auf dem Formular steht, und ruft dann die Nummer an, die man gelesen hat. Wenn diese Zeile leer ist, wird nichts unternommen.
Die Programmierung der Benutzeroberfläche funktioniert auf die gleiche Weise. Wenn eine Schaltfläche angeklickt wird, muss das Programm herausfinden, was es als nächstes tun soll. Es sucht nach dem Rückruf. Dieser Rückruf befindet sich zufällig in einem leeren Feld mit der Aufschrift "Hier steht, was zu tun ist, wenn Button1 angeklickt wird".
Die meisten IDEs füllen die Lücke automatisch für Sie aus (schreiben die Basismethode), wenn Sie sie darum bitten (z.B. button1_clicked
). Dieses Leerzeichen kann jedoch jede Methode, die Ihnen gefällt . Sie könnten die Methode run_computations
o butter_the_biscuits
solange Sie den Namen des Rückrufs in das richtige Feld eintragen. Sie könnten "555-555-1212" in das Feld für die Notrufnummer eingeben. Das macht zwar nicht viel Sinn, ist aber zulässig.
Letzte Anmerkung: Die leere Zeile, die Sie mit dem Rückruf ausfüllen? Sie kann nach Belieben gelöscht und neu geschrieben werden. (ob man das sollte oder nicht, ist eine andere Frage, aber das ist ein Teil ihrer Macht)
- See previous answers
- Weitere Antworten anzeigen