webentwicklung-frage-antwort-db.com.de

Wie kann ich Callback-Funktionen für asynchrones XMLHttpRequest nutzen?

Ich schreibe gerade JavaScript und verwirrt über callback . Ich habe festgestellt, dass es keine eingebauten Funktionen ist ...
Ich lese jetzt O'Relly JavaScript 5th Edition und es zeigt einen Beispielcode, der wie folgt aussieht:

getText = function(url, callback) // How can I use this callback?
{
    var request = new XMLHttpRequest();
    request.onreadystatechange = function()
    {
        if (request.readyState == 4 && request.status == 200)
        {
            callback(request.responseText); // Another callback here
        }
    }
    request.open('GET', url);
    request.send();
}

Im Grunde verstehe ich die allgemeine Idee von callback zwar nicht ... Könnte jemand einen Beispielcode schreiben, um callback zu nutzen?

20
Japboy

Rückrufe sind ziemlich einfach und schick! Aufgrund der Natur von AJAX - Aufrufen blockieren Sie nicht die Ausführung Ihres Skripts, bis Ihre Anforderung abgeschlossen ist (dann wäre sie synchron). Ein Rückruf ist einfach eine Methode, mit der die Antwort behandelt wird, sobald sie zu Ihrer Methode zurückkehrt. 

Da Javascript-Methoden erstklassige Objekte sind, können Sie sie wie Variablen weitergeben.

Also in deinem Beispiel 

getText = function(url, callback) // How can I use this callback?
{
    var request = new XMLHttpRequest();
    request.onreadystatechange = function()
    {
        if (request.readyState == 4 && request.status == 200)
        {
            callback(request.responseText); // Another callback here
        }
    }; 
    request.open('GET', url);
    request.send();
}

function mycallback(data) {
   alert(data);
}

getText('somephpfile.php', mycallback); //passing mycallback as a method

Wenn Sie das oben genannte tun, bedeutet dies, dass Sie mycallback als Methode übergeben, die Ihre Antwort behandelt (Callback).

EDIT

Während das Beispiel hier nicht den richtigen Nutzen eines Rückrufs veranschaulicht (Sie könnten die Warnung doch einfach in die onReadyStateChange-Funktion setzen!), Ist die Nutzbarkeit sicherlich ein Faktor. 

Man muss bedenken, dass es hier wichtig ist, dass JS-Methoden erstklassige Objekte sind. Das bedeutet, dass Sie sie wie Objekte weitergeben und an alle Arten von Ereignissen anhängen können. Wenn Ereignisse ausgelöst werden, werden die mit diesen Ereignissen verbundenen Methoden aufgerufen. 

Wenn Sie request.onreadystatechange = function(){} tun, ordnen Sie diese Methode nur zu, wenn das entsprechende Ereignis ausgelöst wird. 

Die coole Sache hier ist, dass diese Methoden wiederverwendet werden können. Angenommen, Sie haben eine Fehlerbehandlungsmethode, die bei einer 404 in der Anforderung AJAX eine Warnung anzeigt und einige Felder der HTML-Seite auffüllt. 

Wenn Sie Callbacks nicht zuweisen oder Methoden nicht als Parameter übergeben können, müssen Sie den Fehlerbehandlungscode immer wieder schreiben. Stattdessen müssen Sie ihn lediglich als Rückruf zuweisen, und die gesamte Fehlerbehandlung wird sortiert auf einmal. 


44
JohnP

Zunächst einmal würde ich vorschlagen, was ein Rückruf ist. Hier ist ein Anfang.

Das große Bild

Callbacks werden bei der asynchronen Programmierung umfangreich verwendet. Wenn Sie nicht blockieren möchten, bis eine (möglicherweise) lang andauernde Operation abgeschlossen ist, besteht eine der Möglichkeiten, das Problem zu lösen, darin, die Operation an jemanden zu delegieren, der diese Aufgabe für Sie erledigt. Dies wirft die Frage auf: Wie können Sie erkennen, wann die Operation abgeschlossen ist, und wie Sie die Ergebnisse erhalten?

Eine Lösung wäre, die Arbeit an jemand anderen zu delegieren und ab und zu einen Moment von Ihrer normalen Arbeit zu nehmen und zu fragen: "Ist die Arbeit, die ich Ihnen gegeben habe, schon erledigt?". Wenn ja, holen Sie sich die Ergebnisse in irgendeiner Weise und los geht's. Problem gelöst.

Das Problem bei diesem Ansatz ist, dass er Ihr Leben nicht viel einfacher macht. Sie sind jetzt gezwungen, immer wieder zu fragen, und Sie werden nicht wissen, dass die Operation ausgeführt wird, sobald sie tatsächlich erfolgt ist (aber nur beim nächsten Mal, wenn Sie daran denken, zu fragen). Wenn Sie vergessen zu fragen, werden Sie niemals benachrichtigt.

Eine bessere Lösung hierfür ist der Rückruf: Wenn Sie Arbeit delegieren, stellen Sie eine Funktion bereit. Der Code, der die Arbeit tatsächlich do wird, verspricht dann, diese Funktion aufzurufen, sobald die Arbeit abgeschlossen ist. Sie können jetzt alles über dieses Zeug vergessen und sicher sein, dass Ihr Callback nach Abschluss der Arbeit aufgerufen wird. Bald und nicht später.

Was ist der Rückruf hier?

In diesem speziellen Fall ist callback eine Funktion, die Sie getText zur Verfügung stellen, um eine Kommunikation mit Ihnen zu ermöglichen. Sie sagen im Grunde "erledigen Sie diese Arbeit für mich, und wenn Sie fertig sind, können Sie mich hier anrufen.".

getText wählt diesen Callback eigentlich nur dann, wenn die XMLHttpRequest (XHR) abgeschlossen ist, und gleichzeitig "informiert" Sie den Inhalt der HTTP-Antwort (so dass Sie auf diese Informationen reagieren können).

Rückrufe und noch mehr Rückrufe, oh mein!

Aber nehmen Sie sich einen Moment Zeit, um den Code zu lesen. Welchen Wert speichert es in request.onreadystatechange? Was ist der Zweck von request.onreadystatechange?

Die Antwort ist, dass request.onreadystatechange für Sie zum Auffüllen mit einem Rückruf vorhanden ist. Tatsächlich gibt Ihnen XHR die Möglichkeit, ihm einen Rückruf zu geben, und es verspricht, Sie immer dann zurückzurufen, wenn sich der Status der zugrunde liegenden HTTP-Anforderung ändert.

getText ist eine Funktion, die eine Abstraktion bildet darüber hinaus: Sie fügt ihren eigenen Callback (eine anonyme Funktion - ich werde das als "inner") dort ein akzeptiert ein anderer Callback von Ihnen (der Parameter - ich werde ihn als "äußere" bezeichnen). Wenn der innere Rückruf (der sich daran erinnert, dass er bei jeder Statusänderung aufgerufen wird) feststellt, dass der Status "abgeschlossen" ist (die Bedeutung des Werts 4) und der HTTP-Antwortstatuscode 200 lautet (was "OK" bedeutet), ruft er auf der äußere Rückruf, damit Sie, der Benutzer von getText, das Ergebnis erfahren.

Ich hoffe ich mache Sinn. :)

17
Jon

Ich persönlich bevorzuge Event Listener lieber als Rückrufe.

Die Verwendung von Listenern ist besonders praktisch, wenn Sie mehrere asynchrone Anfragen gleichzeitig bearbeiten möchten.

Die Verwendung ist wie folgt (entnommen aus https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest )

function reqListener () {
  console.log(this.responseText);
}

var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send()
1
Mikolas Pansky

Was auf eine Art "Rückruf" funktioniert, ist die Definition eines Dienstes, der ein solches Versprechen zurückgibt!

$http.head("url2check").then(function () {
                return true;
            }, function () {
                return false;
            });

In der Steuerung verwenden Sie den Dienst:

<service>.<service method>.then(function (found)) {
     if (found) {......
}

@jon ist korrekt, um es asynchron zu nennen! 

0
Sydwell

XMLHttpRequest-Rückruffunktion und Hochladen von Dateien mit Datenarray

function HttpPost(url, arr, cb, form){
    if (form === undefined) { var data = new FormData(); }else{ var data = new FormData(form); }
    if (arr !== undefined) {
        for (const index in arr) {    
            data.append(index, arr[index]);
        }
    }
    var hr = new XMLHttpRequest();        
    hr.onreadystatechange=function(){
        if (hr.readyState==4 && hr.status==200){
            if( typeof cb === 'function' ){ cb(hr.responseText); }
        }
    }
    hr.upload.onprogress = function(e) {
        var done = e.position || e.loaded, total = e.totalSize || e.total;
        console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
    };
    hr.open("POST",url,true);
    hr.send(data);
}

// HttpPost callback
function cb_list(res){
    console.log(res);
    var json = JSON.parse(res);
    console.log(json.id + ' ' + json.list);
    // loop
    for (var objindex in json.list){
        console.log(json.list[objindex].id);
    }
}

Stichprobe:

var data = [];
data["cmd"] = "get-cos";
var form = $('#form')[0];

HttpPost('/api-load', data, cb_list, form);

<form id="form" method="POST" enctype="multipart/form-data">
    <input type="file" name="file[]" multiple accept="image/*">
</form>

HTTP-Header-Inhalt

hr.setRequestHeader("Content-Type", "application/json"); 
// data:
var json = {"email": "[email protected]", "password": "101010"}
var data = JSON.stringify(json);

hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// data: 
var data = "fname=Henry&lname=Ford";
0
Dingo