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


Ich habe eine Funktion foo was eine Ajax Anfrage macht. Wie kann ich die Antwort zurücksenden? foo?

Ich habe versucht, den Wert aus der success Callback sowie das Zuweisen der Antwort an eine lokale Variable innerhalb der Funktion und die Rückgabe dieser, aber keine dieser Möglichkeiten gibt tatsächlich die Antwort 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`.

4307
2018-01-08 17:06


Ursprung


Antworten:


-> Eine allgemeinere Erklärung des asynchronen Verhaltens mit verschiedenen Beispielen finden Sie unter  Warum wird meine Variable nicht geändert, nachdem ich sie in einer Funktion geändert habe? - Asynchrone Code-Referenz 

-> Wenn Sie das Problem bereits verstanden haben, fahren Sie mit den folgenden Lösungsvorschlägen fort.

Das Problem

Das EIN im Ajax steht für asynchron . Das bedeutet, dass das Senden der Anfrage (oder vielmehr das Empfangen der Antwort) aus dem normalen Ausführungsablauf herausgenommen wird. In Ihrem Beispiel $.ajax kehrt sofort und die nächste Aussage zurück, return result;, wird vor der Funktion ausgeführt, die Sie als übergeben haben success Rückruf wurde sogar angerufen.

Hier ist eine Analogie, die hoffentlich den Unterschied zwischen synchronem und asynchronem Fluss-Clearer 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 könnte, wartest du am Telefon und starrst ins Leere, bis dein Freund dir die Antwort gibt, die du brauchst.

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

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

var item = findItem();

// Do something with item
doSomethingElse();

Obwohl findItem Es könnte eine lange Zeit dauern, um Code auszuführen, der danach kommt var item = findItem(); muss warten bis die Funktion das Ergebnis zurückgibt.

Asynchron

Du rufst deinen Freund aus demselben Grund wieder an. Aber dieses Mal sagst du ihm, dass du es eilig hast und er sollte Ruf dich zurück auf deinem Handy. Du hängst auf, gehst aus dem Haus und tust, was immer du vorhast. Sobald dein Freund dich zurück ruft, hast du es mit den Informationen zu tun, die er dir gegeben hat.

Genau das passiert, wenn Sie eine Ajax-Anfrage machen.

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, a Rückrufen (etwas bemerken? Rückrufen ?). Jede Anweisung, die nach diesem Aufruf kommt, wird ausgeführt, bevor der Callback aufgerufen wird.


Lösung (en)

Umarmen Sie die asynchrone Natur von JavaScript! Während bestimmte asynchrone Operationen synchrone Gegenstücke zur Verfügung stellen (so auch "Ajax"), wird im Allgemeinen davon abgeraten, sie zu verwenden, insbesondere in einem Browserkontext.

Warum ist es schlecht, fragst du?

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

All dies ist eine sehr schlechte Benutzererfahrung. Der Benutzer wird nicht erkennen können, ob alles in Ordnung ist oder nicht. Außerdem wird der Effekt für Benutzer mit einer langsamen Verbindung schlechter.

Im Folgenden betrachten wir drei verschiedene Lösungen, die aufeinander aufbauen:

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

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


ES2017 +: Versprechen mit async/await

Die neue Version von ECMAScript wurde im Jahr 2017 veröffentlicht Unterstützung auf Syntaxebene für asynchrone Funktionen. Mit der Hilfe von async und await, können Sie asynchron in einem "synchronen Stil" schreiben. Machen Sie aber keinen Fehler: Der Code ist immer noch asynchron, aber es ist einfacher zu lesen / zu verstehen.

async/await baut auf Versprechen auf: a async Funktion gibt immer ein Versprechen zurück. await "wickelt" ein Versprechen ab und führt entweder zu dem Wert, mit dem das Versprechen gelöst wurde, oder es wird ein Fehler ausgegeben, wenn das Versprechen abgelehnt wurde.

Wichtig: Sie können nur verwenden await in einem async Funktion. Das bedeutet, dass Sie auf oberster Ebene direkt mit dem Versprechen arbeiten müssen.

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

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 a second (just for the sake of this example)
    await delay(1000);
    // 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);
  });

Neuere Browser und Knoten Versionen unterstützen async/await. Sie können auch ältere Umgebungen unterstützen, indem Sie Ihren Code mithilfe von ES5 in ES5 umwandeln Regenerator (oder Tools, die Regenerator verwenden, wie z Babel).


Lassen Sie Funktionen akzeptieren Rückrufe

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

Im Beispiel der Frage können Sie machen foo Akzeptieren Sie einen Rückruf und verwenden Sie ihn als success Rückrufen. 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, an die wir gehen foo wenn wir es nennen und wir geben es einfach weiter success. I.e. Sobald die Ajax-Anfrage erfolgreich ist, $.ajax werde anrufen callback und leiten Sie die Antwort an den Rückruf (der mit bezeichnet werden kann) result, denn so haben wir den Callback definiert).

Sie können die Antwort auch vor dem Weiterleiten an den Rückruf bearbeiten:

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

Es ist einfacher, Code mit Rückrufen zu schreiben, als es scheint. Immerhin ist JavaScript im Browser stark ereignisgesteuert (DOM-Ereignisse). 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 sich den Anwendungsfluss durchdenken.


ES2015 +: Versprechen mit dann()

Das Promise-API ist ein neues Feature von ECMAScript 6 (ES2015), aber es ist gut Browser-Unterstützung bereits. Es gibt auch viele Bibliotheken, die die Standard-Promises-API implementieren und zusätzliche Verfahren bereitstellen, um die Verwendung und Zusammensetzung von asynchronen Funktionen (z. Bluebird).

Versprechen sind Behälter für Zukunft Werte. Wenn das Versprechen den Wert erhält (ist es aufgelöst) oder wenn es storniert wird (abgelehnt), benachrichtigt es alle seine "Zuhörer", die auf diesen Wert zugreifen wollen.

Der Vorteil gegenüber einfachen Callbacks ist, dass Sie Ihren Code entkoppeln können und einfacher zu komponieren 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 solche Versprechen 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
  });

Die Beschreibung aller Vorteile, die das Versprechen bietet, sprengt den Rahmen dieser Antwort. Wenn Sie jedoch neuen Code schreiben, sollten Sie sie ernsthaft in Betracht ziehen. Sie bieten eine große Abstraktion und Trennung Ihres Codes.

Weitere Informationen zu Versprechungen: HTML5 rockt - JavaScript-Versprechen

Randnotiz: jQuerys verzögerte Objekte

Zurückgestellte Objekte sind jQuerys benutzerdefinierte Implementierung von Versprechen (bevor die Promise-API standardisiert wurde). Sie verhalten sich fast wie Versprechen, legen aber eine etwas andere API offen.

Jede Ajax-Methode von jQuery gibt bereits ein "verzögertes Objekt" (eigentlich ein Versprechen eines verzögerten 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
});

Randnotiz: Promise Gotchas

Beachten Sie, dass Versprechen und verzögerte Objekte gerecht sind Behälter Für einen zukünftigen Wert sind sie nicht der 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 missversteht die obigen Asynchronitätsprobleme. Speziell, $.ajax() friert den Code nicht ein, während er die Seite "/ password" auf Ihrem Server überprüft - er sendet eine Anfrage an den Server und während er wartet, gibt er sofort ein jQuery Ajax Deferred-Objekt zurück, nicht die Antwort vom Server. Das bedeutet die if Anweisung wird immer dieses verzögerte Objekt erhalten, behandeln Sie es als trueund fahren fort, als ob der Benutzer angemeldet ist. Nicht gut.

Aber die Lösung 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: Synchrone "Ajax" -Aufrufe

Wie ich bereits erwähnt habe, haben einige (!) Asynchrone Operationen synchrone Gegenstücke. Ich befürworte ihre Verwendung nicht, aber um der Vollständigkeit willen, hier ist, wie Sie einen synchronen Aufruf ausführen würden:

Ohne jQuery

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

jQuery

Wenn du benutzt jQuerykannst du das einstellen async Option zu false. Beachten Sie, dass diese Option ist veraltet seit jQuery 1.8. Sie können dann entweder noch einen verwenden success Rückruf oder Zugriff auf die responseText Eigentum der jqXHR-Objekt:

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

Wenn Sie eine andere jQuery Ajax-Methode verwenden, z $.get, $.getJSONusw. müssen Sie es ändern $.ajax(da Sie nur Konfigurationsparameter an ... übergeben können $.ajax).

Kopf hoch! Es ist nicht möglich, eine Synchronisierung durchzuführen JSONP anfordern. JSONP ist von Natur aus immer asynchron (ein Grund mehr, diese Option nicht einmal in Erwägung zu ziehen).


4654
2018-01-08 17:06



Wenn du bist nicht Mit jQuery in Ihrem Code ist diese Antwort für Sie

Ihr Code sollte in etwa 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 gemacht und eine Antwort für Leute geschrieben, die jQuery für AJAX benutzen. Ich habe mich entschieden, eine Alternative für Leute anzubieten, die das nicht tun.

(Hinweis für diejenigen, die das neue verwenden fetch API, Angular oder Versprechungen, die ich unten eine andere Antwort hinzugefügt habe)


Was du vor dich stellst

Dies ist eine kurze Zusammenfassung von "Erklärung des Problems" von der anderen Antwort, wenn Sie nicht sicher sind, nachdem Sie dies gelesen haben, lesen Sie das.

Das EIN in AJAX steht für asynchron. Das bedeutet, dass das Senden der Anfrage (oder vielmehr das Empfangen der Antwort) aus dem normalen Ausführungsablauf herausgenommen wird. In Ihrem Beispiel .send kehrt sofort und die nächste Aussage zurück, return result;, wird vor der Funktion ausgeführt, die Sie als übergeben haben success Rückruf wurde sogar angerufen.

Dies bedeutet, dass der von Ihnen definierte Listener bei der Rückkehr noch nicht ausgeführt wurde, was bedeutet, dass der Wert, den Sie zurückgegeben haben, nicht definiert wurde.

Hier ist eine einfache Analogie

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

(Geige)

Der Wert von a zurückgegeben ist undefined seit der a=5 Teil wurde noch nicht ausgeführt. AJAX verhält sich so: Sie geben den Wert zurück, bevor der Server Ihrem Browser mitteilen kann, um welchen Wert es sich handelt.

Eine mögliche Lösung für dieses Problem ist der Code reaktiv , dem Programm mitteilen, 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);
}

Das nennt man CPS. Im Grunde gehen wir vorüber getFive Eine Aktion, die ausgeführt wird, wenn sie abgeschlossen ist. Wir teilen unserem Code mit, wie er reagieren soll, wenn ein Ereignis abgeschlossen ist (wie unser AJAX-Aufruf oder in diesem Fall das Zeitlimit).

Verwendung wäre:

getFive(onComplete);

Das sollte "5" auf dem Bildschirm alarmieren. (Geige).

Mögliche Lösungen

Es gibt im Wesentlichen zwei Möglichkeiten, dies zu lösen:

  1. Machen Sie den AJAX-Aufruf synchron (nennen wir es SJAX).
  2. Strukturieren Sie Ihren Code so, dass er ordnungsgemäß mit Callbacks funktioniert.

1. Synchron AJAX - Mach es nicht !!

Wie für synchrone AJAX, mach es nicht! Felix 'Antwort wirft einige zwingende Argumente auf, warum es eine schlechte Idee ist. Zusammenfassend wird der Browser des Benutzers eingefroren, bis der Server die Antwort zurückgibt und eine sehr schlechte Benutzererfahrung erzeugt. Hier ist eine weitere kurze Zusammenfassung von MDN:

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

Kurz gesagt, synchrone Anfragen blockieren die Ausführung von Code ... ... das kann ernsthafte Probleme verursachen ...

Wenn du haben Um es zu tun, können Sie eine Flagge übergeben: Hier ist, wie:

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. Code umstrukturieren

Lassen Sie Ihre Funktion einen Rückruf annehmen. Im Beispielcode foo kann dazu gebracht werden, einen Rückruf anzunehmen. Wir werden unserem Code sagen, wie reagieren wann foo schließt ab.

Damit:

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 gut einen Verweis auf eine bestehende 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 Callback-Design durchgeführt wird, finden Sie in Felix 'Antwort.

Nun, lassen Sie uns foo selbst definieren, 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();
}

(Geige)

Wir haben nun unsere foo-Funktion so konfiguriert, dass sie eine Aktion akzeptiert, 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 ist und entsprechend handeln (einen Fehlerbehandler erstellen usw.). Unser Problem effektiv lösen.

Wenn es Ihnen immer noch schwer fällt, das zu verstehen Lesen Sie den AJAX-Leitfaden für Erste Schritte bei MDN.


886
2018-05-29 23:30



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

Wenn Sie jQuery nicht verwenden und ein nettes kurzes XMLHttpRequest 2 wollen, das sowohl auf modernen Browsern als auch auf mobilen Browsern funktioniert, schlage ich vor, es so zu verwenden:

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 (keine unnötigen Schließungen).
  3. Es verwendet das neue Onload (Sie müssen also nicht nach dem Fertigstatus && Status suchen)
  4. Es gibt einige andere Situationen, an die ich mich nicht erinnere, die das XMLHttpRequest 1 ärgern.

Es gibt zwei Möglichkeiten, die Antwort dieses Ajax-Aufrufs zu erhalten (drei, die den Name der XMLHttpRequest-Variable verwenden):

Das einfachste:

this.response

Oder wenn Sie aus irgendeinem Grund bind() der Rückruf zu einer Klasse:

e.target.response

Beispiel:

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

Oder (das obige ist besser anonyme Funktionen sind immer ein Problem):

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

Nichts einfacher.

Jetzt werden einige Leute wahrscheinlich sagen, dass es besser ist, onreadystatechange oder den Namen der XMLHttpRequest-Variable zu verwenden. Das ist falsch.

Auschecken XMLHttpRequest erweiterte Funktionen

Es wird auf allen * modernen Browsern unterstützt. Und ich kann bestätigen, wie ich diesen Ansatz verwende, da XMLHttpRequest 2 existiert. Ich hatte nie ein Problem in allen Browsern, die ich verwende.

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

Verwendung der XMLHttpRequest Der Variablenname ist ein weiterer großer Fehler, da Sie den Callback innerhalb der onload / oreadystatechange-Closures ausführen müssen, sonst haben Sie ihn verloren.


Wenn Sie jetzt mit post und FormData etwas Komplexeres wollen, können Sie diese Funktion einfach 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)
}

Wiederum ... es ist eine sehr kurze Funktion, aber es bekommt & post.

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 setzen Sie einige benutzerdefinierte Werte:

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

Wie Sie sehen können, habe ich keine Synchronisierung implementiert ... es ist eine schlechte Sache.

Nachdem ich das gesagt habe ... warum machen Sie es nicht einfach?


Wie im Kommentar erwähnt, bricht die Verwendung des Fehlers && synchron den Punkt der Antwort vollständig durch. Was ist ein schöner kurzer Weg um Ajax richtig zu benutzen?

Fehlerbehandlung

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, so dass die Funktion nicht beeinträchtigt wird. Der Error-Handler kann auch für andere Funktionen verwendet werden.

Aber um wirklich einen Fehler zu bekommen, der nur Der Weg ist eine falsche URL zu schreiben. In diesem Fall gibt jeder Browser einen Fehler aus.

Fehlerhandler sind vielleicht nützlich, wenn Sie benutzerdefinierte Header setzen, den responseType auf Blob-Array-Puffer setzen oder was auch immer ....

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

Selbst wenn Sie "fdggggilfdghfldj" als formdata übergeben, wird kein Fehler ausgegeben.

Im ersten Fall liegt der Fehler innerhalb der displayAjax() unter this.statusText wie Method not Allowed.

Im zweiten Fall funktioniert es einfach. Sie müssen auf der Server-Seite prüfen, ob Sie die richtigen Post-Daten übergeben haben.

Cross-Domain nicht erlaubt wirft Fehler automatisch.

In der Fehlerreaktion gibt es keine Fehlercodes.

Es gibt nur die this.type was auf Fehler gesetzt ist.

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

Also: Sie müssen keine Fehler finden, wenn Sie die URL korrekt kopieren und einfügen können. ;)

PS: Als ersten Test habe ich x ('x', displayAjax) geschrieben ... und es hat total eine Antwort bekommen ... ??? Also überprüfte ich den Ordner, in dem sich der HTML befindet, und es gab eine Datei namens "x.xml". Selbst wenn Sie die Erweiterung Ihrer Datei vergessen haben, wird XMLHttpRequest 2 FIND IT. 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 nette große TXT-Datei 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 keinen anderen Weg, dies asynchron zu tun. (Ja, mit setTimeout Schleife ... aber ernsthaft?)

Ein weiterer Punkt ist ... wenn Sie mit APIs arbeiten oder Sie nur Listen-Dateien besitzen oder was auch immer Sie für jede Anfrage verschiedene Funktionen verwenden ...

Nur wenn Sie eine Seite haben, auf der Sie immer das gleiche XML / JSON laden oder was auch immer Sie brauchen nur eine Funktion. In diesem Fall ändern Sie etwas die Ajax-Funktion und ersetzen Sie b durch Ihre spezielle Funktion.


Die oben genannten Funktionen sind für den grundlegenden Gebrauch.

Wenn Sie die Funktion ERWEITERN möchten ...

Ja, du kannst.

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

Aber mit XMLHttpRequest 2 können Sie eine Menge tun:

Ich habe einen Download-Manager (Bereiche auf beiden Seiten mit Lebenslauf verwenden, Filereader, Dateisystem), Konverter verschiedenen Bild resizers mit Leinwand, websql Datenbanken mit base64images bevölkern und vieles mehr ... Aber in diesen Fällen sollen Sie eine Funktion nur zu diesem Zweck erstellen ... manchmal brauchen Sie einen Blob, Array-Puffer, Sie können Header setzen, Mime-Typ überschreiben und es gibt viel mehr ...

Aber die Frage ist, wie man eine Ajax-Antwort zurückgibt ... (Ich fügte einen einfachen Weg hinzu.)


302
2017-08-19 08:06



Wenn Sie Versprechungen verwenden, ist diese Antwort für Sie.

Das bedeutet AngularJS, jQuery (mit aufgeschobener), native XHR Nachfolger (Fetch), EmberJS, Backbone.js des speichern oder einen beliebigen Knoten-Bibliothek, die Versprechen zurückgibt.

Ihr Code sollte in etwa so aussehen:

function foo() {
    var data;
    // or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // result is always undefined no matter what.

Felix Kling hat eine gute Arbeit geleistet und eine Antwort für Leute geschrieben, die jQuery mit Callbacks für AJAX nutzen. Ich habe eine Antwort für native XHR. Diese Antwort bezieht sich auf die allgemeine Verwendung von Versprechen im Frontend oder Backend.


Das Kernproblem

Das JavaScript-Concurrency-Modell im Browser und auf dem Server mit NodeJS / io.js ist asynchron und reaktiv.

Wann immer Sie eine Methode aufrufen, die ein Versprechen zurückgibt, then Handler sind immer asynchron ausgeführt - also nach der Code unter ihnen, der nicht in einem ist .then Handler.

Das bedeutet, wenn du zurückkehrst data das then Der von Ihnen definierte Handler wurde noch nicht ausgeführt. Dies bedeutet wiederum, dass der Wert, den Sie zurückgeben, nicht rechtzeitig auf den richtigen Wert gesetzt wurde.

Hier ist eine einfache Analogie für das Problem:

    function getFive(){
        var data;
        setTimeout(function(){ // set a timer for one second in the future
           data = 5; // after a second, do this
        }, 1000);
        return data;
    }
    document.body.innerHTML = getFive(); // `undefined` here and not 5

Der Wert von data ist undefined seit der data = 5 Teil wurde noch nicht ausgeführt. Es wird wahrscheinlich in einer Sekunde ausgeführt, aber zu diesem Zeitpunkt ist es für den zurückgegebenen Wert irrelevant.

Da die Operation noch nicht ausgeführt wurde (AJAX, Serveraufruf, IO, Timer), geben Sie den Wert zurück, bevor die Anfrage die Möglichkeit hatte, Ihrem Code mitzuteilen, um welchen Wert es sich handelt.

Eine mögliche Lösung für dieses Problem ist der Code reaktiv , dem Programm mitteilen, was zu tun ist, wenn die Berechnung abgeschlossen ist. Versprechen ermöglichen dies aktiv, indem sie zeitlich (zeitabhängig) in der Natur sind.

Kurzer Rückblick auf Versprechungen

Ein Versprechen ist a Wert im Laufe der Zeit. Versprechen haben einen Status, sie beginnen als schwebend ohne Wert und können abrechnen zu:

  • erfüllt Dies bedeutet, dass die Berechnung erfolgreich abgeschlossen wurde.
  • abgelehnt was bedeutet, dass die Berechnung fehlgeschlagen ist.

Ein Versprechen kann nur Staaten wechseln Einmal danach wird es immer für immer im selben Zustand bleiben. Sie können anhängen then Handler zu versprechen, ihren Wert zu extrahieren und Fehler zu behandeln. then Handler erlauben Verkettung von Anrufen. Versprechen werden von erstellt Verwenden von APIs, die sie zurückgeben. Zum Beispiel der modernere AJAX-Ersatz fetch oder jQuery's $.get Versprechen zurückgeben.

Wenn wir anrufen .then auf ein Versprechen und Rückkehr etwas davon - wir bekommen ein Versprechen für der verarbeitete Wert. Wenn wir ein anderes Versprechen abgeben, werden wir erstaunliche Dinge bekommen, aber lasst uns unsere Pferde halten.

Mit Versprechungen

Mal sehen, wie wir das obige Problem mit Versprechungen lösen können. Lasst uns zunächst unser Verständnis von Versprechungszuständen von oben demonstrieren, indem wir die Promise-Konstruktor zum Erstellen einer Verzögerungsfunktion:

function delay(ms){ // takes amount of milliseconds
    // returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // when the time is up
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

Jetzt, nachdem wir setTimeout konvertiert haben, um Versprechungen zu verwenden, können wir verwenden then um es zu zählen:

function delay(ms){ // takes amount of milliseconds
  // returns a new promise
  return new Promise(function(resolve, reject){
    setTimeout(function(){ // when the time is up
      resolve(); // change the promise to the fulfilled state
    }, ms);
  });
}

function getFive(){
  // we're RETURNING the promise, remember, a promise is a wrapper over our value
  return delay(100).then(function(){ // when the promise is ready
      return 5; // return the value 5, promises are all about return values
  })
}
// we _have_ to wrap it like this in the call site, we can't access the plain value
getFive().then(function(five){ 
   document.body.innerHTML = five;
});

Grundsätzlich, anstatt eine zurück zu geben Wert was wir wegen des Nebenläufigkeitsmodells nicht tun können - wir geben ein Verpackung für einen Wert, den wir können auspacken mit then. Es ist wie eine Schachtel, mit der man öffnen kann then.

Dies anwenden

Dies gilt auch für Ihren ursprünglichen API-Aufruf. Sie können:

function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // process it inside the `then`
    });
}

foo().then(function(response){
    // access the value inside the `then`
})

Das funktioniert genauso gut. Wir haben gelernt, dass wir Werte von bereits asynchronen Aufrufen nicht zurückgeben können, aber wir können Versprechungen verwenden und sie verketten, um die Verarbeitung auszuführen. Wir wissen nun, wie die Antwort von einem asynchronen Aufruf zurückgegeben wird.

ES2015 (ES6)

ES6 führt ein Generatoren das sind Funktionen, die in der Mitte zurückkehren und dann den Punkt wieder aufnehmen können, an dem sie waren. Dies ist typischerweise nützlich für Sequenzen, zum Beispiel:

function* foo(){ // notice the star, this is ES6 so new browsers/node/io only
    yield 1;
    yield 2;
    while(true) yield 3;
}

Ist eine Funktion, die ein zurückgibt Iterator über die Sequenz 1,2,3,3,3,3,.... was kann iteriert werden. Während das alleine interessant ist und viel Platz bietet, gibt es einen besonders interessanten Fall.

Wenn die Sequenz, die wir produzieren, eine Folge von Aktionen statt Zahlen ist, können wir die Funktion anhalten, wenn eine Aktion ausgeführt wird, und auf sie warten, bevor wir die Funktion fortsetzen. Also brauchen wir statt einer Zahlenfolge eine Folge von Zukunft Werte - das heißt: Versprechen.

Dieser etwas knifflige, aber sehr mächtige Trick ermöglicht es uns, asynchronen Code synchron zu schreiben. Es gibt mehrere "Runner", die das für Sie tun, eine kurze Codezeile zu schreiben, aber das geht über den Rahmen dieser Antwort hinaus. Ich werde Bluebirds benutzen Promise.coroutine hier, aber es gibt andere Wrapper wie co oder Q.async.

var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // notice the yield
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
});

Diese Methode gibt ein Versprechen selbst zurück, das wir von anderen Korotinen konsumieren können. Beispielsweise:

var main = coroutine(function*(){
   var bar = yield foo(); // wait our earlier coroutine, it returns a promise
   // server call done here, code below executes when done
   var baz = yield fetch("/api/users/"+bar.userid); // depends on foo's result
   console.log(baz); // runs after both requests done
});
main();

ES2016 (ES7)

In ES7 ist dies weiter standardisiert, es gibt momentan mehrere Vorschläge, aber in allen davon können Sie await versprechen. Dies ist nur "Zucker" (schönere Syntax) für den obigen ES6 - Vorschlag, indem man den async und await Schlüsselwörter. Das obige Beispiel machen:

async function foo(){
    var data = await fetch("/echo/json"); // notice the await
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
}

Es gibt immer noch ein Versprechen, genau das gleiche :)


243
2018-05-12 02:22



Sie verwenden Ajax falsch. Die Idee ist nicht, etwas zurückgeben zu lassen, sondern stattdessen die Daten an eine so genannte Callback-Funktion zu übergeben, 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 irgendetwas im Submit-Handler wird nichts bewirken. Sie müssen stattdessen entweder die Daten übergeben oder tun, was Sie wollen, direkt in der Erfolgsfunktion.


192
2018-05-23 02:05



Die einfachste Lösung ist, eine JavaScript-Funktion zu erstellen und sie für Ajax aufzurufen success Rückrufen.

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

184
2018-02-18 18:58



Ich werde mit einem schrecklich aussehenden, handgezeichneten Comic antworten. Das zweite Bild ist der Grund warum result ist undefined in Ihrem Codebeispiel.

enter image description here


154
2017-08-11 14:17



Angular1

Für Leute, die benutzen AngularJS, kann mit dieser Situation umgehen Promises.

Hier es sagt,

Promises können verwendet werden, um asynchrone Funktionen zu verengen, und ermöglicht es, mehrere Funktionen miteinander zu verketten.

Sie können eine schöne Erklärung finden Hier ebenfalls.

Beispiel gefunden in Dokumente unten genannten.

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

Angular2 und später

Im Angular2 mit Blick auf das folgende Beispiel, aber seine empfohlen benutzen Observables mit Angular2.

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

Sie können das auf diese Weise konsumieren,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

Siehe die Original hier posten. Aber Typescript unterstützt nicht native es6 VersprechenWenn Sie es verwenden möchten, benötigen Sie möglicherweise ein Plugin dafür.

Dazu kommt noch das Versprechen Spez Definieren Sie hier.


113
2017-08-26 08:11



Die meisten Antworten hier geben nützliche Vorschläge für den Fall, dass Sie einen einzelnen asynchronen Vorgang ausführen. Dies kann jedoch manchmal auftreten, wenn Sie einen asynchronen Vorgang ausführen müssen jeder Eintrag in einem Array oder einer anderen listenähnlichen Struktur. Die Versuchung ist, dies zu tun:

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

Beispiel:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Der Grund, der nicht funktioniert, ist, dass die Rückrufe von doSomethingAsync Wenn Sie versuchen, die Ergebnisse zu verwenden, sind Sie noch nicht gelaufen.

Wenn Sie also ein Array (oder eine Liste irgendeiner Art) haben und asynchrone Operationen für jeden Eintrag ausführen möchten, haben Sie zwei Möglichkeiten: Führen Sie die Operationen parallel (überlappend) oder nacheinander (nacheinander) aus.

Parallel

Sie können alle starten und verfolgen, wie viele Rückrufe Sie erwarten, und dann die Ergebnisse verwenden, wenn Sie so viele Rückrufe erhalten haben:

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

Beispiel:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Wir könnten damit aufhören expecting und benutze es einfach results.length === theArray.length, aber das lässt uns offen für die Möglichkeit, dass theArray wird geändert, während die Anrufe ausstehen ...)

Beachten Sie, wie wir das verwenden index von forEach um das Ergebnis zu speichern results in derselben Position wie der Eintrag, auf den es sich bezieht, auch wenn die Ergebnisse außerhalb der Reihenfolge eintreffen (da Async-Aufrufe nicht notwendigerweise in der Reihenfolge abgeschlossen werden, in der sie gestartet wurden).

Aber was, wenn Sie müssen Rückkehr diese Ergebnisse von einer Funktion? Wie die anderen Antworten gezeigt haben, können Sie nicht; Sie müssen Ihre Funktion akzeptieren und einen Callback aufrufen (oder a zurückgeben) Versprechen). Hier ist eine Rückrufversion:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

Beispiel:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Oder hier ist eine Version, die eine zurückgibt Promise stattdessen:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Natürlich, wenn doSomethingAsync gab uns Fehler, die wir verwenden würden reject das Versprechen abzulehnen, wenn wir einen Fehler bekommen haben.)

Beispiel:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Oder alternativ könnten Sie einen Wrapper für doSomethingAsync das gibt ein Versprechen, und dann tun Sie das unten ...)

Ob doSomethingAsync gibt dir ein Versprechenkannst du benutzen Promise.all:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Beispiel:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Beachten Sie, dass Promise.all Englisch: www.mjfriendship.de/en/index.php?op...39&Itemid=32 Seine Verheißung löst sie mit einer Reihe von Ergebnissen aller Versprechen, die sie ihr geben, wenn sie alle gelöst sind, oder sie lehnt ihr Versprechen ab, wenn das Deutsch: zuerst von den Versprechen, die du ihm gibst, weist er zurück.

Serie

Angenommen, Sie möchten nicht, dass die Operationen parallel sind? Wenn Sie sie nacheinander ausführen möchten, müssen Sie darauf warten, dass jede Operation abgeschlossen ist, bevor Sie mit der nächsten beginnen. Hier ist ein Beispiel für eine Funktion, die das tut und einen Callback mit dem Ergebnis aufruft:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(Da wir die Arbeit in Serie machen, können wir einfach verwenden results.push(result) weil wir wissen, dass wir keine Ergebnisse außerhalb der Reihenfolge bekommen werden. Oben hätten wir gebraucht results[index] = result;, aber in einigen der folgenden Beispiele haben wir keinen zu verwendenden Index.)

Beispiel:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Oder, wiederum, erstellen Sie einen Wrapper für doSomethingAsync das gibt dir ein Versprechen und mach das unten ...)

Ob doSomethingAsync gibt Ihnen ein Versprechen, wenn Sie ES2017 + Syntax verwenden können (vielleicht mit einem Transpiler wie Babel), können Sie ein async Funktion mit for-of und await:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Beispiel:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Wenn Sie die ES2017 + -Syntax (noch) nicht verwenden können, können Sie eine Variation der "Promise reduzieren" -Muster (Dies ist komplexer als die üblichen Promise-Reduzierungen, da wir das Ergebnis nicht von einem in das andere übergeben, sondern stattdessen ihre Ergebnisse in einem Array sammeln):

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Beispiel:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

... die weniger umständlich ist ES2015 + Pfeilfunktionen:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Beispiel:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}


90
2018-05-03 16:59



Schau dir 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 du siehst getJoke ist Rückgabe eines aufgelöst versprechen (Es ist bei der Rückkehr gelöst res.data.value). Also wartest du bis zum $ http.get Anfrage ist abgeschlossen und dann console.log (res.joke) wird ausgeführt (als normaler asynchroner Ablauf).

Das ist der PLNKR:

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


73
2018-06-02 08:31