2016-08-02 13 views
1

Ich fand den Begriff "The Ghost Promise" here, die wie mein Fall aussieht.Wie man das Verheißungs-Antimuster repariert - Ghost Promise?

Ich habe den Code wie folgt:

return Q.Promise(function(resolve, reject) { 
    firstFunctionThatReturnPromise() 
    .then(function(firstResult) { 
    _check(firstResult) ? resolve(firstResult) : return secondFunctionThatReturnPromise(); 
    }) 
    .then(function(secondResult) { 
    console.log(secondResult); 
    return thirdFunctionThatReturnPromise(secondResult); 
    }) 
    .then(function(thirdResult) { 
    resolve(thirdResult); 
    }) 
    .catch(function(e) { 
    reject(e) 
    }); 
}); 

Das Problem ist, auch wenn die _check kehrt wahr, es geht nach wie vor zu dem console.log Befehl (der in undefined führt).

Wenn die _check false zurückgibt, funktionieren die Dinge wie erwartet.

Also meine Frage ist:

  • Wenn das oben beschriebene Verhalten ist normal?
  • Gibt es eine elegantere Art, diesen Fall zu behandeln?

Update 1: Viele in Frage gestellt, warum ich Q.Promise stattdessen das Ergebnis direkt zurückzugeben. Dies liegt daran, dass dies eine generische Funktion ist, die von anderen Funktionen gemeinsam genutzt wird.

// Usage in other functions 
genericFunction() 
.then(function(finalResult) { 
    doSomething(finalResult); 
}) 
.catch(function(err) { 
    handleError(err); 
}); 
+0

Sie habe hier keinen Geist, sondern einen einfachen ['Promise' Konstruktor Antipattern] (http://stackoverflow.com/q/23803743/1048572)! – Bergi

Antwort

2

Zunächst einmal gibt es keinen Grund, ein neues Versprechen um dieses Thema zu legen. Ihre Operationen geben bereits Versprechen zurück, so dass es ein error prone anti-pattern ist, sie in ein neues Versprechen umzuwickeln.

Sekunde aus, wie andere gesagt haben, ein .then() Handler hat diese Möglichkeiten:

  1. Es kann ein Ergebnis zurück, die auf die nächsten .then() Handler übergeben werden. Wenn nichts zurückgegeben wird, wird undefined an den nächsten .then() Handler übergeben.
  2. Es kann eine Zusage zurückgeben, deren aufgelöster Wert an den nächsten -Handler übergeben wird, oder der abgelehnte Wert wird an den nächsten Zurückweisungs-Handler übergeben.
  3. Es kann werfen, die das aktuelle Versprechen zurückweisen wird.

Es gibt keine Möglichkeit, von einem .then() Handler einem Versprechen Kette zu sagen, bedingt einig folgenden .then() Handler andere als Ablehnung zu überspringen.

Also, wenn Sie auf Basis Ihrer Versprechen verzweigen wollen auf eine Bedingung Logik, dann müssen Sie tatsächlich Nest Ihre .then() Handler nach Ihren Verzweigungslogik:

a().then(function(result1) { 
    if (result1) { 
     return result1; 
    } else { 
     // b() is only executed here in this conditional 
     return b().then(...); 
    } 
}).then(function(result2) { 
    // as long as no rejection, this is executed for both branches of the above conditional 
    // result2 will either be result1 or the resolved value of b() 
    // depending upon your conditional 
}) 

Also, wenn Sie verzweigen wollen Sie erstellen eine neue verschachtelte Kette, mit der Sie steuern können, was auf der Grundlage der bedingten Verzweigung geschieht.

mit Ihrem psuedo-Code, würde es in etwa so aussehen:

firstFunctionThatReturnPromise().then(function (firstResult) { 
    if (_check(firstResult)) { 
     return firstResult; 
    } else { 
     return secondFunctionThatReturnPromise().then(function (secondResult) { 
      console.log(secondResult); 
      return thirdFunctionThatReturnPromise(secondResult); 
     }) 
    } 
}).then(function (finalResult) { 
    console.log(finalResult); 
    return finalResult; 
}).catch(function (err) { 
    console.log(err); 
    throw err; 
}); 

Auch wenn dies in einem genericFunction ist, können Sie immer noch nur das Versprechen zurückkehren Sie bereits haben:

function genericFunction() { 
    return firstFunctionThatReturnPromise().then(function (firstResult) { 
     if (_check(firstResult)) { 
      return firstResult; 
     } else { 
      return secondFunctionThatReturnPromise().then(function (secondResult) { 
       console.log(secondResult); 
       return thirdFunctionThatReturnPromise(secondResult); 
      }) 
     } 
    }).then(function (finalResult) { 
     console.log(finalResult); 
     return finalResult; 
    }).catch(function (err) { 
     console.log(err); 
     throw err; 
    }); 
} 

// usage 
genericFunction().then(...).catch(...) 
+0

Danke für deine Antwort, ich bearbeite meine Frage, um den Grund hinzuzufügen, warum ich den Versprechenswrapper verwende. – haipham23

+1

@ haipham23 - Ich sehe immer noch keinen Grund, dies in ein Versprechen zu verpacken. Du scheinst nicht zu verstehen, dass du kein neues Versprechen machen musst, um es zurückzugeben. Du kannst einfach das zurückgeben, das du bereits hast, wie meine Antwort zeigt. – jfriend00

+0

Danke, ich folge Ihrer Anweisung oben und es funktioniert perfekt! – haipham23

0

Ich habe noch nie Q verwendet, aber alles, was ein Versprechen zurück in ein Versprechen umgewandelt und an die nächsten .then() geben. Hier geben Ihre ersten .then() nichts zurück. So gibt es undefined zurück. So undefined ist in einem neuen Promise verpackt und an den nächsten Handler übergeben, wo Sie secondResult == undefined erhalten.

Sie können es in Aktion in den folgenden CodePen sehen: http://codepen.io/JesmoDrazik/pen/xOaXKE

1

Das Verhalten erwartet wird. Wenn Sie Ihre -Anweisungen verketten, können Sie nicht vorzeitig aus der Kette ausbrechen, außer durch einen Fehler.

Ihr Top-Level-Versprechen (das von Q.Promise() zurückgegebene) wird nach _check() aufgelöst; aber Sie haben tatsächlich eine innere Versprechungskette, die weiterhin ausgeführt wird.

Durch Spezifikation, then() gibt ein Versprechen: https://promisesaplus.com/#point-40

Sie für sich selbst in den Quellcode von Q sehen: https://github.com/kriskowal/q/blob/v1/q.js#L899

Für Ihre gewünschte Verhalten, müssen Sie tatsächlich eine weitere verschachtelte Versprechen Kette.

return Q.Promise(function(resolve, reject) { 
    firstFunctionThatReturnPromise().then(function(firstResult) { 
    if (_check(firstResult)) { 
     resolve(firstResult); 
    } else { 
     return secondFunctionThatReturnPromise().then(function(secondResult) { 
     console.log(secondResult); 
     return thirdFunctionThatReturnPromise(secondResult); 
     }); 
    } 
    }); 
}); 
+2

Da alle Funktionen bereits Versprechen versprechen, müssen sie nicht mit "Q.Promise" umschlossen werden. Geben Sie einfach das Versprechen von 'firstFunctionThatReturnPromise' zurück (und geben Sie' firstResult' zurück, da es automatisch umbrochen wird). – robertklep

Verwandte Themen