2014-02-05 9 views
26

In meinem Code, basierend auf einer bestimmten Bedingung, möchte ich auf die done Funktion überspringen, unabhängig von allen then Funktionen.Korrekter Weg zum Überspringen einer Dann-Funktion in Q Promises

Die ursprüngliche Version dieser Frage befindet sich in den Änderungen. Das Folgende ist das eigentliche Problem, mit dem ich es zu tun habe. Es tut uns leid

tatsächliche Problem:

ich eine Datei lese und es zu verarbeiten. Wenn der Inhalt der Datei bestimmte Bedingungen erfüllt, muss ich eine Reihe von Operationen auf dem Dateisystem ausführen (sagen Sie, lesen und schreiben Sie einige Dateien) und dann done Funktion ausführen. Wenn die Bedingungen fehlschlagen, muss ich alle Reihe von Operationen überspringen und ich muss die done Funktion direkt ausführen.

ich ein Objekt zurückgeben (läßt result sagen) in allen then Funktionen und in den nächsten then ich aktualisiere result und es zurück. Also, wenn alle then fertig sind, wird done die angesammelten result haben. Schließlich wird doneresult verarbeiten und ausdrucken. Wenn die Bedingungen nicht erfüllt sind, wird done einfach result (die leer wäre) drucken.

Q() 
.then(readFile) 
.then(function (contents) { 
    var processResult = process the contents; 
    if (processResult) { 
     return {}; 
    } else { 
     // How can I skip to `done` from here 
    } 
}) 
.then(function (results) { 
    // do some more processing and update results 
    return results; 
}) 
... // Few more then functions similar to the one above 
... 
.fail(function (exception) { 
    console.error(exception.stack); 
}) 
.done(function (results) { 
    // do some more processing and update results 
    console.log(results); 
}); 
+0

Nicht sicher, aber können Sie nicht ein Objekt zurückgeben, das einen booleschen Wert enthält, abhängig von diesem booleschen Wert wird Ihre nächste Funktion ja/nein ausführen. \t 'return { \t \t random: ..., \t \t Prozess: true \t};', in Ihren Anruf nächsten dann: '.then (function (data) { \t if (data.process) \t \t Rückkehr; \t \t Rückkehr data.randomNumber + 1; }) ' – Dieterg

+0

@DieterGoetelen, dass, obwohl die nächste Verarbeitungsfunktion extrem abhängig von dem vorherigen Schritt machen würde. – poke

+0

Könnten Sie bitte ein realeres Problem verwenden (vielleicht Ihre eigentliche Aufgabe, es wäre in Ordnung mit viel Pseudocode von dem, was passiert)? Ihr synchrones Beispiel macht nicht wirklich viel Sinn. – Bergi

Antwort

23

es ein bisschen hängt davon ab, was die Bedingungen sind zu überspringen, welche Art von Operationen, die Sie tun, und wie „nützlich“ ist das Ganze, wenn die Bedingungen gescheitert. Sie können hier möglicherweise eine intelligente Zurückweisung verwenden, um die Nachricht zu vermitteln. Ansonsten glaube ich, dass der richtige Weg, um damit umzugehen, wirklich eine verschachtelte Menge von Versprechensanrufen ist.

Dies entspricht auch der core idea behind promises, die synchrone Kontrollstrukturen zur asynchronen Codeausführung zurückbringen soll. Im Allgemeinen sollten Sie bei der Verwendung von Versprechen zuerst darüber nachdenken, wie Sie die Aufgabe mit dem synchronen Code ausführen würden. Und wenn Sie über Ihre Situation denken, wäre es wahrscheinlich wie folgt arbeiten:

var contents = readFromFile(); 
var results = initialOperation(contents); 
if (fancyCondition(results)) { 
    results = doSomething(results); 
    results = doMore(results); 
} 
processAndPrint(results); 

So würden Sie in eine echte Niederlassung haben in Synchroncode. Als solches macht es keinen Sinn, dass Sie das in asynchronem Code mit Versprechungen vermeiden möchten. Wenn Sie einfach nur überspringen könnten Dinge, Sie waren im Wesentlichen mit Sprüngen mit GOTOS. Stattdessen verzweigen Sie sich und machen einige andere Dinge separat.

Also zurück zu Versprechen und asynchronen Code, eine tatsächliche Zweigstelle mit einem anderen Satz von verketteten Operationen ist völlig in Ordnung, und im Geiste der Absicht hinter Versprechen.So könnte obigen Code wie folgt aussehen:

readFromFile(fileName) 
.then(initialOperation) 
.then(function (results) { 
    if (fancyCondition(results) { 
     return doSomething(results) 
      .then(doMore); 
    } 
    return results; 
}) 
.catch(errorHandler) 
.then(processResults) 
.then(outputResults); // Or `done` in Q 

Beachten Sie auch, dass das Versprechen Pipeline automatisch viel mehr sauberer aussieht, wenn Sie mit den Funktionen starten, die Versprechungen auf ihre eigenen zurückkehren, anstatt sie zu schaffen Inline von then.

1

Wenn ich „überspringen“ richtig, dann ist die generische Lösung ist nicht zurück Wert unter „überspringen“ Bedingungen zu verstehen, so dass der Eingangswert ermöglicht wird, durch transparent zu passieren.

zB:

...then(function (randomInteger) { 
    var remainder = randomInteger % 2; 
    console.log(['Even','Odd'][remainder] + ' number: ', randomInteger); 
    if(remainder) { 
     return randomInteger + 1; 
    } 
})... 
+0

Aber das wird immer noch die nächste 'then' Funktion ausführen, oder? Einziger Unterschied wäre, Argumente sind "{" 0 ": undefiniert}'. – thefourtheye

+0

Ja, Sie müssten einige "überspringen" -Logik in jedem .then() 'Erfolgshandler anwenden. Das ist die Natur einer '.then()' Kette. –

+0

Und Nein nicht 'undefiniert', wie gesagt, der Eingabewert wird weitergegeben, wenn keine Rückgabe erfolgt. –

9

Aber dann verschachteln wir die thenable Funktionen. Das wollten wir in erster Linie durch Versprechungen vermeiden.

Nein, das ist in der Tat der richtige Weg. Für Verzweigung benötigen Sie immer eine zusätzliche Verschachtelungsebene. Wenn der Einzug zu groß wird, können Sie immer noch den alten Trick des Aufrufs von Unterprozeduren anwenden (der auch für die Wiederverschlüsselung von Callback-Funktionen verwendet wird).


Andere Lösungen sind ziemlich hässlich. Überspringen von ein paar then -Handlern in einer Kette, ohne tiefere Verschachtelung, kann getan werden, indem man eine Ausnahme wirft und das Versprechen zurückweist; Dies könnte dann am Ende gefangen werden. Es könnte für ein paar Szenarien gelten, aber ich halte das nicht für eine gute Idee.

Die andere Möglichkeit, die ich denken könnte würde das bedingte Ergebnis in eine andere Datenstruktur, die durch die Kette von then s übergeben werden könnte. Dies wäre wie Maybe in Haskell oder Option in Scala, und Sie würden map über sie in den Handlern. Dies würde jedoch auch eine zusätzliche Verschachtelungsebene erfordern, wäre weniger effizient, um nichts explizit durch die Kette zu propagieren, und hätte Probleme mit zurückgegebenen Versprechen in der Kette.

0

Ich verwende eine Kontextvariable und implementiere die Bedingungslogik in Funktionen, die innerhalb der Versprechungskette aufgerufen werden. Jede Funktion gibt dieselbe Kontextvariable zurück. Dies hält die Versprechenskette aufgeräumt. Die Verwendung von Funktionsnamen, die auf die bedingten Tests hinweisen, verbessert die Lesbarkeit.

Verwandte Themen