javascript - variable - return type of ajax call




Wie gebe ich die Antwort von einem asynchronen Anruf zurück? (20)

Ich habe eine Funktion foo , die eine Ajax-Anfrage macht. Wie kann ich die Antwort von foo ?

Ich habe versucht, den Wert aus dem success sowie die Antwort einer lokalen Variablen in der Funktion zuzuweisen und diese zurückzugeben, aber keine dieser Methoden gibt die Antwort tatsächlich zurück.

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;
}

var result = foo(); // It always ends up being `undefined`.

→ Eine allgemeinere Erklärung des asynchronen Verhaltens mit verschiedenen Beispielen finden Sie unter Warum ist meine Variable unverändert, nachdem ich sie innerhalb einer Funktion geändert habe? - Asynchrone Codereferenz

→ Wenn Sie das Problem bereits verstanden haben, fahren Sie mit den nachstehenden Lösungen fort.

Das Problem

Das A in Ajax steht für asynchronous . Das heißt, das Senden der Anfrage (bzw. das Empfangen der Antwort) wird aus dem normalen Ausführungsablauf genommen. In Ihrem Beispiel gibt $.ajax sofort zurück und die nächste Anweisung gibt das return result; , wird ausgeführt, bevor die Funktion, die Sie als success sogar aufgerufen wurde.

Hier ist eine Analogie, die hoffentlich den Unterschied zwischen synchronem und asynchronem Fluss klarer macht:

Synchron

Stellen Sie sich vor, Sie telefonieren mit einem Freund und bitten ihn, etwas für Sie zu suchen. Obwohl es eine Weile dauern kann, warten Sie am Telefon und starren in den Weltraum, bis Ihr Freund Ihnen die Antwort gibt, die Sie benötigen.

Das Gleiche passiert, wenn Sie einen Funktionsaufruf mit "normalem" Code ausführen:

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

Obwohl die findItem sehr lange dauern kann, wird jeder Code, der nach var item = findItem(); muss warten, bis die Funktion das Ergebnis zurückgibt.

Asynchron

Sie rufen Ihren Freund aus demselben Grund erneut an. Aber diesmal sagen Sie ihm, dass Sie es eilig haben und er Sie über Ihr Mobiltelefon zurückrufen sollte. Sie legen auf, verlassen das Haus und tun, was Sie geplant haben. Sobald Ihr Freund Sie zurückruft, beschäftigen Sie sich mit den Informationen, die er Ihnen gegeben hat.

Genau das passiert bei einer Ajax-Anfrage.

findItem(function(item) {
    // Do something with item
});
doSomethingElse();

Anstatt auf die Antwort zu warten, wird die Ausführung sofort fortgesetzt und die Anweisung nach dem Ajax-Aufruf ausgeführt. Um die Antwort schließlich zu erhalten, stellen Sie eine Funktion bereit, die aufgerufen werden soll, sobald die Antwort empfangen wurde, ein Rückruf (etwas Rückruf beachten). Jede nach diesem Aufruf kommende Anweisung wird ausgeführt, bevor der Rückruf aufgerufen wird.

Lösung (en)

Umfassen Sie die asynchrone Natur von JavaScript! Bestimmte asynchrone Operationen bieten zwar synchrone Gegenstücke (dies gilt auch für "Ajax"), es wird jedoch generell davon abgeraten, sie zu verwenden, insbesondere im Browser-Kontext.

Warum ist es schlecht, fragst du?

JavaScript wird im Benutzeroberflächenthread des Browsers ausgeführt. Bei einem längeren Prozess wird die Benutzeroberfläche gesperrt, so dass sie nicht mehr reagiert. Darüber hinaus gibt es eine Obergrenze für die Ausführungszeit von JavaScript, und der Browser fragt den Benutzer, ob die Ausführung fortgesetzt werden soll oder nicht.

All dies ist eine wirklich schlechte Benutzererfahrung. Der Benutzer kann nicht feststellen, ob alles einwandfrei funktioniert oder nicht. Darüber hinaus wird der Effekt für Benutzer mit einer langsamen Verbindung schlechter sein.

Im Folgenden werden drei verschiedene Lösungen betrachtet, die alle aufeinander aufbauen:

  • Versprechen mit async/await (ES2017 +, in älteren Browsern verfügbar, wenn Sie einen Transpiler oder einen Regenerator verwenden)
  • Rückrufe (in Knoten beliebt)
  • Versprechen mit then() (ES2015 +, verfügbar in älteren Browsern, wenn Sie eine der vielen Versprechenbibliotheken verwenden)

Alle drei sind in aktuellen Browsern und Knoten 7+ verfügbar.

ES2017 +: Versprechen mit async/await Erwarten

Mit der 2017 veröffentlichten Version von ECMAScript wurde die Unterstützung für asynchrone Funktionen auf Syntaxebene eingeführt. Mit Hilfe von async und await können Sie asynchron in einem "synchronen Stil" schreiben. Der Code ist immer noch asynchron, aber einfacher zu lesen / zu verstehen.

async/await baut auf Versprechungen auf: Eine async Funktion liefert immer ein Versprechen. Erwarten Sie, dass ein Versprechen "auspackt", und führen Sie entweder zu dem Wert, mit dem das Versprechen gelöst wurde, oder wirft einen Fehler aus, wenn das Versprechen abgelehnt wurde.

Wichtig: Sie können async nur innerhalb einer async Funktion verwenden. Das bedeutet, dass Sie auf oberster Ebene immer noch direkt mit dem Versprechen arbeiten müssen.

Sie können mehr über async/await lesen und auf MDN await .

Hier ist ein Beispiel, das auf der obigen Verzögerung aufbaut:

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}


async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for 3 seconds (just for the sake of this example)
    await delay();
    // GET information about each book
    return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
  } catch(error) {
    // If any of the awaited promises was rejected, this catch block
    // would catch the rejection reason
    return null;
  }
}

// Async functions always return a promise
getAllBooks()
  .then(function(books) {
    console.log(books);
  });

Aktuelle browser und node unterstützen async/await . Sie können auch ältere Umgebungen unterstützen, indem Sie Ihren Code mithilfe des regenerator (oder von Tools, die den Regenerator verwenden, z. B. Babel ) in ES5 umwandeln.

Lassen Sie Funktionen Rückrufe annehmen

Ein Rückruf ist einfach eine Funktion, die an eine andere Funktion übergeben wird. Diese andere Funktion kann die übergebene Funktion aufrufen, wenn sie bereit ist. Im Kontext eines asynchronen Prozesses wird der Callback immer dann aufgerufen, wenn der asynchrone Prozess ausgeführt wird. Normalerweise wird das Ergebnis an den Rückruf übergeben.

Im Beispiel der Frage können Sie einen Rückruf von foo annehmen und als success . Also das

var result = foo();
// Code that depends on 'result'

wird

foo(function(result) {
    // Code that depends on 'result'
});

Hier haben wir die Funktion "Inline" definiert, aber Sie können eine beliebige Funktionsreferenz übergeben:

function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

foo selbst ist wie folgt definiert:

function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

callback bezieht sich auf die Funktion, die wir an foo wenn wir sie aufrufen, und wir geben sie einfach an den success . $.ajax also die Ajax-Anforderung erfolgreich ist, $.ajax den callback und $.ajax die Antwort an den Rückruf weiter (auf den mit result verwiesen werden kann, da wir den Rückruf so definiert haben).

Sie können die Antwort auch verarbeiten, bevor Sie sie an den Rückruf übergeben:

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}

Es ist einfacher, mit Callbacks Code zu schreiben, als es den Anschein hat. Schließlich ist JavaScript im Browser stark ereignisgesteuert (DOM-Ereignisse). Das Empfangen der Ajax-Antwort ist nichts anderes als ein Ereignis.
Schwierigkeiten können auftreten, wenn Sie mit Code von Drittanbietern arbeiten müssen. Die meisten Probleme können jedoch gelöst werden, indem Sie einfach den Anwendungsablauf durchdenken.

ES2015 +: Versprechen mit then()

Die then() ist eine neue Funktion von ECMAScript 6 (ES2015), verfügt jedoch bereits über eine gute Browserunterstützung . Es gibt auch viele Bibliotheken, die die Standard-API von Promises implementieren und zusätzliche Methoden bereitstellen, um die Verwendung und Zusammensetzung asynchroner Funktionen (z. B. bluebird ) zu vereinfachen.

Versprechen sind Container für zukünftige Werte. Wenn das Versprechen den Wert erhält (es wird aufgelöst ) oder wenn es storniert ( abgelehnt ) wird, werden alle "Listener" benachrichtigt, die auf diesen Wert zugreifen möchten.

Der Vorteil gegenüber einfachen Rückrufen besteht darin, dass Sie Ihren Code entkoppeln können und einfacher zu erstellen sind.

Hier ist ein einfaches Beispiel für die Verwendung eines Versprechens:

function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected 
    // (it would not happen in this example, since `reject` is not called).
  });

Bei unserem Ajax-Aufruf könnten wir Versprechen wie folgt verwenden:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("/echo/json")
  .then(function(result) {
    // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });

Das Beschreiben aller Vorteile, die Versprechen bieten, sprengt den Rahmen dieser Antwort. Wenn Sie jedoch neuen Code schreiben, sollten Sie ihn ernsthaft in Betracht ziehen. Sie bieten eine hervorragende Abstraktion und Trennung Ihres Codes.

Weitere Informationen zu Versprechen: HTML5-Felsen - JavaScript-Versprechen

Randbemerkung: Die zurückgestellten Objekte von jQuery

Verzögerte Objekte sind die benutzerdefinierte Implementierung von Versprechungen von jQuery (bevor die Promise-API standardisiert wurde). Sie verhalten sich fast wie Versprechungen, weisen jedoch eine etwas andere API auf.

Jede Ajax-Methode von jQuery gibt bereits ein "verzögertes Objekt" (eigentlich ein Versprechen eines zurückgestellten Objekts) zurück, das Sie einfach von Ihrer Funktion zurückgeben können:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

Randbemerkung: Versprechen Sie Gotchen

Denken Sie daran, dass Versprechen und zurückgestellte Objekte nur Container für einen zukünftigen Wert sind, nicht aber den Wert selbst. Angenommen, Sie hatten Folgendes:

function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

Dieser Code versteht die oben genannten Probleme mit der Asynchronität nicht. Insbesondere $.ajax() den Code nicht ein, während er die Seite '/ password' auf Ihrem Server überprüft. Er sendet eine Anforderung an den Server und gibt während des Wartens sofort ein jQuery Ajax Deferred-Objekt zurück, nicht die Antwort von der Server. Das heißt, die if Anweisung holt dieses zurückgestellte Objekt immer, behandelt es als true und fährt fort, als wäre der Benutzer angemeldet. Nicht gut.

Aber das Update ist einfach:

checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});

Nicht empfohlen: Synchron "Ajax" -Aufrufe

Wie bereits erwähnt, haben einige (!) Asynchrone Operationen synchrone Gegenstücke. Ich plädiere nicht für deren Verwendung, aber der Vollständigkeit halber würden Sie einen synchronen Aufruf durchführen:

Ohne jQuery

Wenn Sie ein XMLHTTPRequest Objekt direkt verwenden, übergeben Sie false als drittes Argument an .open .

jQuery

Wenn Sie jQuery , können Sie die Option async auf false . Beachten Sie, dass diese Option seit jQuery 1.8 veraltet ist. Sie können dann entweder weiterhin einen success oder auf die responseText -Eigenschaft des jqXHR-Objekts zugreifen :

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

Wenn Sie eine andere jQuery-Ajax-Methode wie $.get , $.getJSON usw. verwenden, müssen Sie sie in $.ajax (da Sie nur Konfigurationsparameter an $.ajax ).

Kopf hoch! Es ist nicht möglich, eine synchrone JSONP Anforderung zu JSONP . JSONP ist von Natur aus immer asynchron (ein Grund mehr, diese Option nicht in Betracht zu ziehen).


Js ist ein einzelner Thread.

Der Browser kann in drei Teile unterteilt werden:

1) Ereignisschleife

2) Web-API

3) Ereigniswarteschlange

Event-Loop wird für immer ausgeführt, dh eine Art Endlos-Loop. Event-Warteschlange ist die Position, in der alle Ihre Funktion auf ein Event gedrückt wird (Beispiel: click). Dies wird einer nach dem anderen aus der Warteschlange ausgeführt und in eine Event-Schleife eingefügt, die diese Funktion ausführt und sich selbst vorbereitet for next one after first wird ausgeführt. Dies bedeutet, dass die Ausführung einer Funktion erst gestartet wird, wenn die Funktion ausgeführt wird, bevor sie in der Warteschlange in der Ereignisschleife ausgeführt wird.

Nehmen wir nun an, wir hätten zwei Funktionen in eine Warteschlange gestellt, eine für das Abrufen von Daten vom Server, und eine andere verwendet diese Daten. Wir haben die Funktion serverRequest () zuerst in die Warteschlange gestellt und dann die Funktion useiseData (). Die serverRequest-Funktion geht in eine Ereignisschleife und ruft den Server an, da wir nie wissen, wie viel Zeit erforderlich ist, um Daten vom Server abzurufen. Es wird also erwartet, dass dieser Prozess Zeit in Anspruch nimmt. Daher beschäftigen wir uns mit unserer Ereignisschleife und hängen unsere Seite auf Die API kommt in die Rolle, dass sie diese Funktion aus der Ereignisschleife übernimmt und befasst sich mit dem Server, der die Ereignisschleife frei macht, so dass wir die nächste Funktion aus der Warteschlange ausführen können. Die nächste Funktion in der Warteschlange ist utiliseData (), die in einer Schleife abläuft, aber aufgrund fehlender Daten nicht Verschwendung und Ausführung der nächsten Funktion wird bis zum Ende der Warteschlange fortgesetzt (dies wird als asynchrones Aufrufen bezeichnet, dh wir können etwas anderes tun, bis wir Daten erhalten).

Nehmen wir an, unsere serverRequest () - Funktion hatte eine return-Anweisung in einem Code. Wenn wir Daten vom Server zurückerhalten, wird die Web-API diese am Ende der Warteschlange in die Warteschlange stellen. Da es am Ende der Warteschlange gedrückt wird, können wir seine Daten nicht verwenden, da in der Warteschlange keine Funktion zur Verwendung dieser Daten vorhanden ist. Daher ist es nicht möglich, etwas von Async Call zurückzugeben.

Die Lösung hierfür ist Rückruf oder Versprechen .

Ein Bild aus einer der Antworten hier, erläutert die Verwendung von Rückrufen auf korrekte Weise ... Wir geben unsere Funktion (Funktion, die vom Server zurückgegebene Daten verwendet) an den aufrufenden Server weiter.

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}

In meinem Code heißt es als

function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}

Lesen Sie hier die neuen Methoden in ECMA (2016/17) für den asynchronen Anruf (@Felix Kling Answer on Top) https://.com/a/14220323/7579856


Wenn Sie jQuery nicht in Ihrem Code verwenden, ist diese Antwort für Sie

Ihr Code sollte ungefähr so ​​aussehen:

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Felix Kling hat einen guten Job geschrieben und eine Antwort für Leute geschrieben, die jQuery für AJAX verwenden. Ich habe beschlossen, eine Alternative für Leute anzubieten, die dies nicht tun.

( Hinweis: Für diejenigen, die die neue fetch API, Angular oder Versprechen verwenden, habe ich unten eine weitere Antwort hinzugefügt. )

Was Sie vor sich haben

Dies ist eine kurze Zusammenfassung der "Erklärung des Problems" aus der anderen Antwort. Wenn Sie sich nach dem Lesen nicht sicher sind, lesen Sie dies.

Das A in AJAX steht für asynchron . Das heißt, das Senden der Anfrage (bzw. das Empfangen der Antwort) wird aus dem normalen Ausführungsablauf genommen. .send kehrt in Ihrem Beispiel .send zurück und die nächste Anweisung gibt das return result; , wird ausgeführt, bevor die Funktion, die Sie als success sogar aufgerufen wurde.

Das heißt, wenn Sie zurückkehren, wurde der von Ihnen definierte Listener noch nicht ausgeführt. Das bedeutet, dass der von Ihnen zurückgegebene Wert nicht definiert wurde.

Hier ist eine einfache Analogie

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(Fiddle)

Der Wert a zurückgegebenen ist nicht undefined da der a=5 Teil noch nicht ausgeführt wurde. AJAX verhält sich wie folgt: Sie geben den Wert zurück, bevor der Server die Gelegenheit hat, Ihrem Browser mitzuteilen, welchen Wert dieser Wert hat.

Eine mögliche Lösung für dieses Problem besteht darin, den Code erneut zu aktivieren und dem Programm mitzuteilen, was zu tun ist, wenn die Berechnung abgeschlossen ist.

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

Dies wird als CPS . Im Grunde übergeben wir getFive eine Aktion, die ausgeführt wird, wenn es abgeschlossen ist. Wir erklären unserem Code, wie er reagieren soll, wenn ein Ereignis abgeschlossen ist (wie unser AJAX-Aufruf oder in diesem Fall das Zeitlimit).

Verwendung wäre:

getFive(onComplete);

Welches sollte "5" auf dem Bildschirm anzeigen. (Fiddle)

Mögliche Lösungen

Es gibt grundsätzlich zwei Möglichkeiten, dies zu lösen:

  1. Machen Sie den AJAX-Aufruf synchron (nennen wir ihn SJAX).
  2. Umstrukturieren Sie Ihren Code, um ordnungsgemäß mit Rückrufen zu arbeiten.

1. Synchrones AJAX - Tu es nicht !!

Was synchrones AJAX betrifft, tun Sie es nicht! Felix 'Antwort bringt einige überzeugende Argumente vor, warum es eine schlechte Idee ist. Zusammenfassend lässt sich festhalten, dass der Browser des Benutzers eingefroren wird, bis der Server die Antwort zurückgibt und eine sehr schlechte Benutzererfahrung erzeugt. Hier ist eine weitere kurze Zusammenfassung des MDN, warum:

XMLHttpRequest unterstützt sowohl die synchrone als auch die asynchrone Kommunikation. Im Allgemeinen sollten jedoch asynchrone Anforderungen aus Gründen der Performance den synchronen Anforderungen vorgezogen werden.

Kurz gesagt, synchrone Anforderungen blockieren die Ausführung von Code ... ... dies kann ernste Probleme verursachen ...

Wenn Sie es tun müssen, können Sie eine Flagge übergeben: So geht's:

var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. Umstrukturierungscode

Lassen Sie Ihre Funktion einen Rückruf annehmen. Im Beispielcode kann foo einen Rückruf annehmen. Wir werden unserem Code mitteilen, wie er reagieren soll, wenn foo abgeschlossen ist.

So:

var result = foo();
// code that depends on `result` goes here

Wird:

foo(function(result) {
    // code that depends on `result`
});

Hier haben wir eine anonyme Funktion übergeben, aber wir könnten genauso leicht einen Verweis auf eine vorhandene Funktion übergeben, so dass sie wie folgt aussieht:

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

Weitere Informationen dazu, wie diese Art von Rückrufdesign ausgeführt wird, finden Sie in der Antwort von Felix.

Nun definieren wir foo selbst, um entsprechend zu handeln

function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(fiddle)

Wir haben nun unsere foo-Funktion dazu veranlasst, eine Aktion auszuführen, die ausgeführt wird, wenn der AJAX erfolgreich abgeschlossen wurde. Wir können dies weiter ausdehnen, indem wir prüfen, ob der Antwortstatus nicht 200 lautet, und entsprechend handeln (Erstellen eines Fail-Handlers usw.). Unser Problem effektiv lösen.

Wenn Sie immer noch Schwierigkeiten haben, dies zu verstehen, lesen Sie den AJAX-Einführungsleitfaden bei MDN.


Antwort 2017: Sie können jetzt in jedem aktuellen Browser und Knoten genau das tun, was Sie möchten

Das ist ganz einfach:

  • Versprechen Sie
  • Verwenden Sie das await , das JavaScript anweist, um zu erwarten, dass das Versprechen in einen Wert aufgelöst wird (wie die HTTP-Antwort)
  • Fügen Sie der übergeordneten Funktion async/await Schlüsselwort async/await

Hier ist eine funktionierende Version Ihres Codes:

(async function(){

var response = await superagent.get('...')
console.log(response)

})()

Erwarten wird in allen aktuellen Browsern und Knoten 8 unterstützt


Hier sind einige Ansätze für die Arbeit mit asynchronen Anforderungen:

  1. then()
  2. Q - Eine Versprechenbibliothek für JavaScript
  3. A + Promises.js
  4. jQuery verschoben
  5. XMLHttpRequest-API
  6. Callback-Konzept verwenden - Als Implementierung in der ersten Antwort

Beispiel: jQuery verzögerte Implementierung, um mit mehreren Anforderungen zu arbeiten

var App = App || {};

App = {
    getDataFromServer: function(){

      var self = this,
                 deferred = $.Deferred(),
                 requests = [];

      requests.push($.getJSON('request/ajax/url/1'));
      requests.push($.getJSON('request/ajax/url/2'));

      $.when.apply(jQuery, requests).done(function(xhrResponse) {
        return deferred.resolve(xhrResponse.result);
      });
      return deferred;
    },

    init: function(){

        this.getDataFromServer().done(_.bind(function(resp1, resp2) {

           // Do the operations which you wanted to do when you
           // get a response from Ajax, for example, log response.
        }, this));
    }
};
App.init();


XMLHttpRequest 2 (lesen Sie zuerst die Antworten von Benjamin Gruenbaum & Felix Kling)

Wenn Sie jQuery nicht verwenden und ein schönes kurzes XMLHttpRequest 2 wünschen, das sowohl auf modernen Browsern als auch auf mobilen Browsern funktioniert, empfehle ich es folgendermaßen:

function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

Wie du siehst:

  1. Es ist kürzer als alle anderen aufgeführten Funktionen.
  2. Der Rückruf wird direkt eingestellt (also keine zusätzlichen unnötigen Schließungen).
  3. Es verwendet den neuen Onload (Sie müssen also nicht den Status von readystate && überprüfen.)
  4. Es gibt einige andere Situationen, an die ich mich nicht erinnere, die das XMLHttpRequest 1 ärgerlich machen.

Es gibt zwei Möglichkeiten, die Antwort dieses Ajax-Aufrufs abzurufen (drei mit dem Variablennamen XMLHttpRequest):

Das einfachste:

this.response

Oder wenn Sie aus irgendeinem Grund den Callback an eine Klasse bind() :

e.target.response

Beispiel:

function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

Oder (die oben genannten ist besser, anonyme Funktionen sind immer ein Problem):

ajax('URL', function(e){console.log(this.response)});

Nichts einfacher.

Nun werden einige Leute wahrscheinlich sagen, dass es besser ist, onreadystatechange oder sogar den XMLHttpRequest-Variablennamen zu verwenden. Das ist falsch.

Testen Sie die erweiterten Funktionen von XMLHttpRequest

Es wird von allen * modernen Browsern unterstützt. Ich kann dies bestätigen, da ich diesen Ansatz verwende, da XMLHttpRequest 2 existiert. Ich hatte nie Probleme mit allen Browsern, die ich verwende.

onreadystatechange ist nur nützlich, wenn Sie die Header in Status 2 abrufen möchten.

Die Verwendung des Variablennamens XMLHttpRequest ist ein weiterer großer Fehler, da Sie den Callback innerhalb der Schließungen von onload / oreadystatechange ausführen müssen, andernfalls haben Sie ihn verloren.

Wenn Sie nun etwas komplexeres mit post und FormData wünschen, können Sie diese Funktion problemlos erweitern:

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.send(d||null)
}

Nochmal ... es ist eine sehr kurze Funktion, aber es wird & postiert.

Anwendungsbeispiele:

x(url, callback); // By default it's get so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set post data

Oder übergeben Sie ein vollständiges Formularelement ( document.getElementsByTagName('form')[0] ):

var fd = new FormData(form);
x(url, callback, 'post', fd);

Oder legen Sie einige benutzerdefinierte Werte fest:

var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

Wie Sie sehen, habe ich die Synchronisierung nicht implementiert ... das ist eine schlechte Sache.

Nachdem ich das gesagt habe, warum nicht einfach?

Wie im Kommentar erwähnt, zerstört die Verwendung von error && synchron den Punkt der Antwort vollständig. Welches ist ein schöner kurzer Weg, um Ajax richtig einzusetzen?

Fehlerhandler

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.onerror = error;
  c.send(d||null)
}

function error(e){
  console.log('--Error--', this.type);
  console.log('this: ', this);
  console.log('Event: ', e)
}
function displayAjax(e){
  console.log(e, this);
}
x('WRONGURL', displayAjax);

Im obigen Skript haben Sie einen Fehlerhandler, der statisch definiert ist, sodass die Funktion nicht beeinträchtigt wird. Der Fehlerhandler kann auch für andere Funktionen verwendet werden.

Um einen Fehler wirklich zu beheben, besteht der einzige Weg darin, eine falsche URL zu schreiben. In diesem Fall gibt jeder Browser einen Fehler aus.

Fehlerbehandlungsroutinen sind möglicherweise hilfreich, wenn Sie benutzerdefinierte Header festlegen, für responseType den Blob-Array-Puffer oder was auch immer.

Selbst wenn Sie 'POSTAPAPAP' als Methode übergeben, wird kein Fehler ausgegeben.

Selbst wenn Sie 'fdggdgilfdghfldj' als formdata übergeben, wird kein Fehler ausgegeben.

Im ersten Fall befindet sich der Fehler in der displayAjax() unter this.statusText als Method not Allowed .

Im zweiten Fall funktioniert es einfach. Sie müssen auf der Serverseite prüfen, ob Sie die richtigen Nachbearbeitungsdaten übergeben haben.

Domains nicht zulässig, wirft einen Fehler automatisch ab.

In der Fehlerantwort gibt es keine Fehlercodes.

Es gibt nur den this.type der auf error gesetzt ist.

Warum einen Fehlerbehandler hinzufügen, wenn Sie keine Kontrolle über Fehler haben? Die meisten Fehler werden in der Callback-Funktion displayAjax() .

Also: Es ist keine Fehlerprüfung erforderlich, wenn Sie die URL richtig kopieren und einfügen können. ;)

PS: Als ersten Test habe ich x ('x', displayAjax) ... geschrieben, und es hat eine Antwort bekommen ... ??? Also habe ich den Ordner überprüft, in dem sich der HTML-Code befindet, und es gab eine Datei namens 'x.xml'. Auch wenn Sie die Dateierweiterung XMLHttpRequest 2 VERGESSEN . Ich habe laut gelacht

Lesen Sie eine Datei synchron

Tu das nicht

Wenn Sie den Browser für eine Weile blockieren möchten, laden Sie eine schöne große Textdatei synchron.

function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

Jetzt können Sie tun

 var res = omg('thisIsGonnaBlockThePage.txt');

Es gibt keine andere Möglichkeit, dies nicht asynchron auszuführen. (Ja, mit setTimeout-Schleife ... aber ernsthaft?)

Ein weiterer Punkt ist ... wenn Sie mit APIs arbeiten oder einfach nur eigene Listendateien verwenden oder was immer Sie für jede Anfrage mit anderen Funktionen verwenden ...

Nur wenn Sie eine Seite haben, auf die Sie immer dasselbe XML / JSON laden oder was auch immer Sie nur eine Funktion benötigen. Ändern Sie in diesem Fall die Ajax-Funktion ein wenig und ersetzen Sie b durch Ihre Sonderfunktion.

Die oben genannten Funktionen dienen zur Grundnutzung.

Wenn Sie die Funktion ERWEITERN wollen ...

Ja, du kannst.

Ich verwende eine Vielzahl von APIs und eine der ersten Funktionen, die ich in jede HTML-Seite integriere, ist die erste Ajax-Funktion in dieser Antwort, nur mit GET ...

Mit XMLHttpRequest 2 können Sie jedoch viele Dinge erledigen:

Ich habe einen Download-Manager erstellt (mit Bereichen auf beiden Seiten mit Lebenslauf, Dateileiter, Dateisystem), verschiedenen Bild-Resizer-Konvertern mit Canvas, Web-Datenbanken mit Base64images und vielem mehr ... manchmal brauchen Sie einen Blob, Array-Puffer, Sie können Header setzen, den Mimetyp überschreiben und es gibt noch viel mehr ...

Aber die Frage ist, wie man eine Ajax-Antwort zurücksendet ... (Ich habe einen einfachen Weg hinzugefügt).


Lassen Sie uns zuerst den Wald sehen, bevor Sie die Bäume betrachten.

Es gibt viele informative Antworten mit großartigen Details, ich werde keine von ihnen wiederholen. Der Schlüssel zur Programmierung in JavaScript ist zunächst das korrekte mentale Modell der Gesamtausführung.

  1. Ihre Einstiegspunkte werden als Ergebnis eines Ereignisses ausgeführt. Beispielsweise wird ein Skripttag mit Code in den Browser geladen. (Aus diesem Grund müssen Sie sich möglicherweise mit der Bereitschaft der Seite für die Ausführung Ihres Codes befassen, wenn Sie zuerst dom-Elemente erstellen müssen.)
  2. Ihr Code wird bis zum Abschluss ausgeführt - so wie viele asynchrone Aufrufe er ausführt -, ohne dass Sie Ihre Rückrufe ausführen müssen , einschließlich XHR-Anforderungen, Timeouts, dom-Ereignishandlern usw. Jeder dieser Rückrufe, die auf die Ausführung warten, wird in eine Warteschlange gestellt und wartet ihrerseits werden sie ausgeführt, nachdem alle anderen abgefeuerten Ereignisse die Ausführung beendet haben.
  3. Jeder einzelne Rückruf für eine XHR-Anforderung, ein Timeout oder ein dom, nach dem das Ereignis einmal aufgerufen wird, wird dann vollständig ausgeführt.

Die gute Nachricht ist: Wenn Sie diesen Punkt gut verstehen, müssen Sie sich nie um die Rennbedingungen kümmern. In erster Linie sollten Sie vor allem wissen, wie Sie Ihren Code als Antwort auf verschiedene diskrete Ereignisse organisieren und wie Sie diese in einer logischen Sequenz zusammenfassen möchten. Sie können Versprechungen oder ein neues async / await auf höherer Ebene als Werkzeuge zu diesem Zweck verwenden, oder Sie können Ihre eigenen Rollen ausführen.

Sie sollten jedoch keine taktischen Hilfsmittel verwenden, um ein Problem zu lösen, bis Sie mit der tatsächlichen Problemdomäne vertraut sind. Zeichnen Sie eine Karte dieser Abhängigkeiten, um zu wissen, wann sie ausgeführt werden muss. Ein Ad-hoc-Ansatz für all diese Rückrufe zu versuchen, wird Ihnen nicht gut tun.


Schauen Sie sich dieses Beispiel an:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

Wie Sie sehen, getJokeist die Rückgabe eines gelösten Versprechens (wird bei der Rückgabe gelöst res.data.value). Sie warten also, bis die $ http.get- Anforderung abgeschlossen ist und anschließend console.log (res.joke) ausgeführt wird (als normaler asynchroner Fluss).

Dies ist das Programm:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/


Die Frage war:

Wie gebe ich die Antwort von einem asynchronen Anruf zurück?

was kann interpretiert werden als:

Wie kann asynchroner Code synchron aussehen ?

Die Lösung besteht darin, Rückrufe zu vermeiden und eine Kombination aus Versprechungen und Asynchron / Erwartung zu verwenden .

Ich möchte ein Beispiel für eine Ajax-Anfrage geben.

(Obwohl es in Javascript geschrieben werden kann, schreibe ich es lieber in Python und kompiliere es mit Transcrypt zu Javascript . Es wird klar genug sein.)

Aktivieren Sie zunächst die JQuery-Verwendung, um Folgendes zur $Verfügung zu haben S:

__pragma__ ('alias', 'S', '$')

Definieren Sie eine Funktion, die ein Promise zurückgibt , in diesem Fall einen Ajax-Aufruf:

def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()

Verwenden Sie den asynchronen Code so, als wäre er synchron :

async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")

ECMAScript 6 verfügt über 'Generatoren', mit denen Sie problemlos asynchron programmieren können.

function* myGenerator() {
    const callback = yield;
    let [response] = yield $.ajax("https://.com", {complete: callback});
    console.log("response is:", response);

    // examples of other things you can do
    yield setTimeout(callback, 1000);
    console.log("it delayed for 1000ms");
    while (response.statusText === "error") {
        [response] = yield* anotherGenerator();
    }
}

Um den obigen Code auszuführen, führen Sie Folgendes aus:

const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function

Wenn Sie Browser ansprechen möchten, die ES6 nicht unterstützen, können Sie den Code über Babel oder den Schließungscompiler ausführen, um ECMAScript 5 zu generieren.

Der Callback ...argswird in ein Array eingeschlossen und beim Lesen zerstört, damit das Muster Callbacks mit mehreren Argumenten verarbeiten kann. Zum Beispiel mit dem Knoten fs :

const [err, data] = yield fs.readFile(filePath, "utf-8", callback);

Mit ES2017 sollten Sie dies als Funktionsdeklaration haben

async function foo() {
    var response = await $.ajax({url: '...'})
    return response;
}

Und es so ausführen.

(async function() {
    try {
        var result = await foo()
        console.log(result)
    } catch (e) {}
})()

Oder die Versprechen-Syntax

foo().then(response => {
    console.log(response)

}).catch(error => {
    console.log(error)

})

Sie können diese benutzerdefinierte Bibliothek (geschrieben mit Promise) verwenden, um einen Remote-Anruf zu tätigen.

function $http(apiConfig) {
    return new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open(apiConfig.method, apiConfig.url);
        client.send();
        client.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                // Performs the function "resolve" when this.status is equal to 2xx.
                // Your logic here.
                resolve(this.response);
            }
            else {
                // Performs the function "reject" when this.status is different than 2xx.
                reject(this.statusText);
            }
        };
        client.onerror = function () {
            reject(this.statusText);
        };
    });
}

Einfaches Anwendungsbeispiel:

$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});

Anstatt Code auf Sie zu werfen, gibt es zwei Konzepte, die für das Verständnis, wie JS Callbacks und Asynchronität handhabt, ausschlaggebend sind. (Ist das überhaupt ein Wort?)

Das Ereignisschleifen- und Parallelitätsmodell

Es gibt drei Dinge, die Sie beachten sollten. Die Warteschlange; die Ereignisschleife und der Stapel

Im Großen und Ganzen ist die Ereignisschleife wie der Projektmanager. Er überwacht ständig alle Funktionen, die ausgeführt werden sollen, und kommuniziert zwischen der Warteschlange und dem Stapel.

while (queue.waitForMessage()) {
   queue.processNextMessage();
}

Sobald eine Nachricht zum Ausführen einer Nachricht empfangen wurde, wird sie der Warteschlange hinzugefügt. Die Warteschlange ist die Liste der Dinge, die zur Ausführung anstehen (wie Ihre AJAX-Anfrage). stell es dir so vor:

 1. call foo.com/api/bar using foobarFunc
 2. Go perform an infinite loop
 ... and so on

Wenn eine dieser Nachrichten ausgeführt wird, holt sie die Nachricht aus der Warteschlange und erstellt einen Stapel. Der Stapel ist alles, was JS ausführen muss, um die Anweisung in der Nachricht auszuführen. In unserem Beispiel heißt es also, anzurufenfoobarFunc

function foobarFunc (var) {
  console.log(anotherFunction(var));
}

Alles, was foobarFunc ausführen muss (in unserem Fall anotherFunction), wird auf den Stack verschoben . ausgeführt und dann vergessen - die Ereignisschleife geht dann zum nächsten Punkt in der Warteschlange (oder lauscht auf Nachrichten)

Der Schlüssel ist hier die Reihenfolge der Ausführung. Das ist

WANN wird etwas laufen

Wenn Sie mit AJAX einen Anruf an eine externe Partei tätigen oder einen asynchronen Code ausführen (z. B. setTimeout), hängt Javascript von einer Antwort ab, bevor es fortfahren kann.

Die große Frage ist, wann wird es die Antwort bekommen? Die Antwort lautet: Wir wissen es nicht - daher wartet die Ereignisschleife darauf, dass diese Nachricht sagt: "Hey, mach mich laufen". Wenn JS gerade auf diese Nachricht synchron gewartet hat, würde Ihre App einfrieren und saugen. Daher führt JS das nächste Element in der Warteschlange aus, während es darauf wartet, dass die Nachricht wieder der Warteschlange hinzugefügt wird.

Deshalb verwenden wir bei asynchroner Funktionalität sogenannte Callbacks . Es ist ein bisschen wie ein then() im wahrsten Sinne des Wortes. Wie ich verspreche, irgendetwas zurückzugeben, verwendet jQuery bestimmte Callbacks, die aufgerufen werden deffered.done deffered.failund deffered.always(unter anderem). Sie können sie alle here

Sie müssen also eine Funktion übergeben, deren Ausführung zu einem bestimmten Zeitpunkt mit den an sie übergebenen Daten versprochen wird.

Da ein Callback nicht sofort ausgeführt wird, sondern zu einem späteren Zeitpunkt, ist es wichtig, die Referenz an die nicht übergebene Funktion zu übergeben. so

function foo(bla) {
  console.log(bla)
}

die meiste Zeit (aber nicht immer) wirst du foonicht bestehenfoo()

Hoffentlich macht das Sinn. Wenn Sie auf solche Dinge stoßen, die verwirrend erscheinen, empfiehlt es sich, die Dokumentation vollständig zu lesen, um zumindest ein Verständnis davon zu erhalten. Das macht Sie zu einem viel besseren Entwickler.


Die einfachste Lösung ist das Erstellen einer JavaScript-Funktion und das Aufrufen des Ajax- successCallbacks.

function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 

Dies ist ein sehr häufiges Problem, dem wir uns stellen, wenn wir mit den "Mysterien" von JavaScript kämpfen. Lassen Sie mich heute versuchen, dieses Rätsel zu entmystifizieren.

Beginnen wir mit einer einfachen JavaScript-Funktion:

function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here

Dies ist ein einfacher synchroner Funktionsaufruf (bei dem jede Codezeile vor der nächsten in Folge mit ihrem Job beendet wird), und das Ergebnis ist dasselbe wie erwartet.

Lassen Sie uns nun ein wenig Twist hinzufügen, indem wir eine kleine Verzögerung in unsere Funktion einführen, so dass alle Codezeilen nicht der Reihe nach "abgeschlossen" werden. Somit wird das asynchrone Verhalten der Funktion nachgeahmt:

function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

Also los geht's, diese Verzögerung hat die Funktionalität, die wir erwartet hatten, gebrochen. Aber was genau ist passiert? Nun, es ist eigentlich ziemlich logisch, wenn man sich den Code ansieht. Die Funktion foo()gibt bei der Ausführung nichts zurück (der zurückgegebene Wert ist also undefined), startet jedoch einen Timer, der nach 1s eine Funktion ausführt, um 'wohoo' zurückzugeben. Wie Sie sehen, ist der Wert, der bar zugewiesen wird, das sofort zurückgegebene Zeug von foo (), nichts anderes, das später kommt.

Wie gehen wir dieses Problem an?

Fragen wir nach unserer Funktion für ein VERSPRECHEN . Bei Promise geht es wirklich darum, was es bedeutet: Es bedeutet, dass die Funktion Ihnen garantiert, jede Ausgabe zu liefern, die Sie in der Zukunft erhalten. so sehen wir es in Aktion für unser kleines Problem oben:

function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when execution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});

Die Zusammenfassung lautet daher: Um asynchronen Funktionen wie Ajax-basierten Aufrufen usw. entgegenzuwirken, können Sie ein Versprechen für resolveden Wert (den Sie zurückgeben möchten) verwenden. Kurz gesagt, lösen Sie den Wert in asynchronen Funktionen auf , anstatt ihn zurückzugeben .

UPDATE (Versprechen mit async / await)

Neben der Verwendung then/catchvon Versprechen gibt es noch einen weiteren Ansatz. Die Idee ist, eine asynchrone Funktion zu erkennen und darauf zu warten, dass die Versprechen aufgelöst werden , bevor zur nächsten Codezeile übergegangen wird. Es ist immer noch nur promisesunter der Haube, aber mit einem anderen syntaktischen Ansatz. Zum besseren Verständnis finden Sie unten einen Vergleich:

dann / catch version:

function fetchUsers(){
   let users = [];
   getUsers()
   .then(_users => users = _users)
   .catch(err =>{
      throw err
   })
   return users;
 }

Async / Erwartete Version:

  async function fetchUsers(){
     try{
        let users = await getUsers()
        return users;
     }
     catch(err){
        throw err;
     }
  }

Dies ist einer der Bereiche, an denen zwei Arten der Datenbindung , die in vielen neuen JavaScript-Frameworks verwendet werden, für Sie von großem Nutzen sind ...

Wenn Sie also Angular, React oder andere Frameworks verwenden, die zwei Arten der Datenbindung verwenden, ist dieses Problem für Sie einfach behoben. In einfachen Worten, Ihr Ergebnis befindet sich undefinedim ersten Schritt. Sie haben also, result = undefinedbevor Sie die Daten erhalten. Sobald Sie das Ergebnis erhalten, wird es aktualisiert und dem neuen Wert zugewiesen, der als Antwort auf Ihren Ajax-Aufruf gilt.

Aber wie können Sie es in reinem Javascript oder jQuery zum Beispiel tun, wie Sie es in dieser Frage stellten?

Sie können einen verwenden Rückruf , versprechen und vor kurzem beobachtbar es für Sie zu behandeln, zum Beispiel in Versprechen , die wir eine Funktion wie Erfolg haben () oder dann () , die ausgeführt wird, wenn die Daten für Sie bereit, das gleiche mit Rückruf oder abonnieren Funktion auf beobachtbar .

In Ihrem Fall, in dem Sie jQuery verwenden , können Sie beispielsweise Folgendes tun:

$(document).ready(function(){
    function foo() {
        $.ajax({url: "api/data", success: function(data){
            fooDone(data); //after we have data, we pass it to fooDone
        }});
    };

    function fooDone(data) {
        console.log(data); //fooDone has the data and console.log it
    };

    foo(); //call happens here
});

Weitere Informationen finden Sie unter Versprechungen und Observablen, die neuere Wege sind, um async Sachen zu machen.


Ich werde mit einem schrecklich aussehenden, von Hand gezeichneten Comic antworten. Das zweite Bild ist der Grund, warum resultes undefinedin Ihrem Codebeispiel ist.


Kurze Antwort ist, Sie müssen einen Rückruf wie folgt implementieren:

function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});

Sie verwenden Ajax falsch. Die Idee ist, dass nichts zurückgegeben wird, sondern die Daten an eine Callback-Funktion übergeben werden, die die Daten verarbeitet.

Das ist:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

Die Rückgabe von Objekten im Submit-Handler führt zu nichts. Sie müssen stattdessen entweder die Daten weitergeben oder machen, was Sie möchten, und zwar direkt in der Erfolgsfunktion.


Verwenden Sie eine callback()Funktion im foo()Erfolg. Versuchen Sie es auf diese Weise. Es ist einfach und leicht zu verstehen.

var lat = "";
var lon = "";
function callback(data) {
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();




ecmascript-2017