Wie warte ich, bis ein Versprechen beendet ist, bevor ich die Variable einer Funktion zurückgebe?

148

Ich kämpfe immer noch mit Versprechungen, mache aber dank der Community hier einige Fortschritte.

Ich habe eine einfache JS-Funktion, die eine Parse-Datenbank abfragt. Es soll das Array von Ergebnissen zurückgeben, aber aufgrund der asynchronen Natur der Abfrage (daher die Versprechen) kehrt die Funktion vor den Ergebnissen zurück und hinterlässt ein undefiniertes Array.

Was muss ich tun, damit diese Funktion auf das Ergebnis des Versprechens wartet?

Hier ist mein Code:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find({
               success: function(results) {
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               },

               error: function(error) {
               // error is an instance of Parse.Error.
                             console.log("Error");
               }
    });                           

}
mac_55
quelle
3
Sie können auch async / await verwenden. Node unterstützt jetzt async / await out of the box seit Version 7.6
Viliam Simko

Antworten:

66

Anstatt a zurückzugeben, geben resultsArraySie ein Versprechen für ein Ergebnisarray und dann thendas auf der Anrufsite zurück. Dies hat den zusätzlichen Vorteil, dass der Anrufer weiß, dass die Funktion asynchrone E / A ausführt. Die Codierung der Parallelität in JavaScript basiert darauf. Vielleicht möchten Sie diese Frage lesen , um eine umfassendere Vorstellung zu erhalten:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find({});                           

}

// later
resultsByName("Some Name").then(function(results){
    // access results here by chaining to the returned promise
});

Weitere Beispiele für die Verwendung von Analyseversprechen mit Abfragen finden Sie in Parses eigenem Blogbeitrag darüber .

Benjamin Gruenbaum
quelle
Kannst du mir sagen, was das unterstützt? IE9 unterstützt dies?
Sandrina-p
Ja, aber Parse selbst ist größtenteils tot, also gibt es diese @SandrinaPereira. Dies ist Parse Cloud Code.
Benjamin Gruenbaum
1
Ah, das ist also nicht nur reines Javascript? Ich suchte nach einer Möglichkeit, dies zu tun (warten Sie, bis eine Funktion beendet ist, um eine andere zu starten), aber nur mit reinem Javascript.
sandrina-p
Die Frage betrifft den Analysecode, keine Versprechen. Versprechen können (mit einer Bibliothek) in jedem Browser funktionieren. Bluebird läuft in IE6 und Netscape 7.
Benjamin Gruenbaum
1
Ich lese SO seit zwei Tagen und trotzdem hat niemand dies gelöst. Diese akzeptierte Antwort ist dieselbe wie jede andere. Die Funktion gibt ein Versprechen zurück, keinen Wert, wie vom OP angefordert. Warum wird diese Antwort als akzeptiert markiert?
iGanja
19

Was muss ich tun, damit diese Funktion auf das Ergebnis des Versprechens wartet?

Verwenden Sie async/await(NICHT Teil von ECMA6, aber seit Ende 2017 für Chrome, Edge, Firefox und Safari verfügbar, siehe canIuse )
MDN

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

Aufgrund eines Kommentars hinzugefügt: Eine asynchrone Funktion gibt immer ein Versprechen zurück, und in TypeScript würde es so aussehen:

    async function waitForPromise(): Promise<string> {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }
Martin Meeser
quelle
4
Die asynchrone Funktion gibt weiterhin ein Versprechungsobjekt zurück, wenn sie ohne Wartezeit (oder in nicht asynchronem Code) aufgerufen wird. Überprüfen Sie das Ergebnis von console.log (waitForPromise ()), wenn Sie sich nicht sicher sind. Eine Überprüfung von console.log (Ergebnis) innerhalb der Asynchron - Funktion wird auszudrucken , was Sie erwarten, aber die Rückkehr von der Asynchron - Funktion geschieht sofort , ohne zu blockieren und gibt ein Versprechen. Das Blockieren in Javascript ist normalerweise sehr schlecht, da es sich um eine Single-Threaded-Anwendung handelt und das Blockieren alle anderen Pub- / Sub-Clients von Benachrichtigungen abhält, die im Wesentlichen die gesamte App in die Knie zwingen.
SRM
1
.net hat .wait () auf der "Versprechen" -ähnlichen Taskklasse. Fehlt Javascript diese Funktion? Ich muss auf etwas warten, bevor ich das Befehlszeilentool meines Knotens beende, das seine Ausgabe möglicherweise an ein anderes Tool weiterleitet. "Warten" funktioniert nur in asynchronen Funktionen. Das heißt, es funktioniert nicht außerhalb des Rahmens eines Versprechens.
TamusJRoyce
@SRM Ich glaube, Ihr Kommentar basiert auf einer Fehlinterpretation des Beispiels - es geht um die "innere" Promise.resolve (als einfachstes Promise-Beispiel), sodass es keinen äußeren Anrufer gibt, wie Sie in Ihrem Kommentar angeben. Also habe ich beschlossen, die Antwort zu aktualisieren.
Martin Meeser
@TamusJRoyce Vermutlich ist das eine Frage für sich, aber ich denke, in C # können Sie Task.ContinueWith (Task) verwenden. Dies ist die gleiche Idee, die Sie in der akzeptierten Antwort sehen (wo sie "then ()" heißt).
Martin Meeser
Ich denke ich sehe jetzt. Ich kann mein gesamtes Skript in eine riesige asynchrone Funktion einbinden. Und nenne diese Funktion die letzte Zeile meines Skripts. Diese Funktion wäre immer noch ein bisschen Kesselplatte. Aber viel weniger als ich bisher wahrgenommen habe. Ich bin es nicht gewohnt, Funktionen innerhalb von Funktionen zu schreiben. Vielen Dank an MartinMeeser!
TamusJRoyce
3

Sie möchten die Funktion nicht warten lassen, da JavaScript nicht blockierend sein soll. Geben Sie das Versprechen lieber am Ende der Funktion zurück, dann kann die aufrufende Funktion das Versprechen verwenden, um die Serverantwort zu erhalten.

var promise = query.find(); 
return promise; 

//Or return query.find(); 
Spur
quelle
1
Ihre ganze Rückrufsache mit dem success:Bit ist aus.
Benjamin Gruenbaum
Oder besser : return query.find();.
Brei
Auch ok. Ich lasse es nur zur Veranschaulichung so, füge es aber als Kommentar hinzu.
Trace
Ich habe es versucht, aber die Ergebnisse scheinen undefiniert zu sein. resultsByName ("name"). then (function (results) {console.log ("got array" + results.count);});
Mac_55
1
Vielen Dank, es muss ein Fehler in der Ergebnisfunktion aufgetreten sein. Es funktioniert jetzt. Ich habe mein console.log in results.length geändert und kann sehen, dass es 1 Eintrag in meinem zurückgegebenen Array gibt :)
mac_55
2

Sie verwenden hier eigentlich keine Versprechen. Mit Parse können Sie Rückrufe oder Versprechen verwenden. deine Entscheidung.

Gehen Sie wie folgt vor, um Versprechen zu verwenden:

query.find().then(function() {
    console.log("success!");
}, function() {
    console.log("error");
});

Um nun Dinge auszuführen, nachdem das Versprechen abgeschlossen ist, können Sie es einfach innerhalb des Versprechen-Rückrufs innerhalb des then()Anrufs ausführen . Bisher wäre dies genau das gleiche wie bei normalen Rückrufen.

Um Versprechen wirklich gut zu nutzen, müssen Sie sie wie folgt verketten:

query.find().then(function() {
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
}, function() {
    console.log("error");
}).then(function() {
    console.log("success on second callback!");
}, function() {
    console.log("error on second callback");
});
Maische
quelle
Welcher Objekttyp ist das Ergebnisobjekt? da es mein Array nicht zu enthalten scheint
mac_55
Es sollte ein Array von Parse.Object's sein.
Brei