Ich habe Code geschrieben, der etwas tut, das so aussieht:
function getStuffDone(param) { | function getStuffDone(param) {
var d = Q.defer(); /* or $q.defer */ | return new Promise(function(resolve, reject) {
// or = new $.Deferred() etc. | // using a promise constructor
myPromiseFn(param+1) | myPromiseFn(param+1)
.then(function(val) { /* or .done */ | .then(function(val) {
d.resolve(val); | resolve(val);
}).catch(function(err) { /* .fail */ | }).catch(function(err) {
d.reject(err); | reject(err);
}); | });
return d.promise; /* or promise() */ | });
} | }
Jemand hat mir gesagt, dass dies als " verzögertes Antimuster " bzw. " Promise
Konstruktor-Antimuster " bezeichnet wird. Was ist schlecht an diesem Code und warum wird dies als Antimuster bezeichnet ?
javascript
promise
q
bluebird
es6-promise
Benjamin Gruenbaum
quelle
quelle
getStuffDone
Funktionsumbruch entfernt und nur das Promise-Literal verwendet?catch
Block imgetStuffDone
Wrapper das Antimuster?Promise
Beispiel haben Sie auch unnötige Funktions-Wrapper für die.then
und.catch
Handler (dh es könnte einfach sein.then(resolve).catch(reject)
). Ein perfekter Sturm von Anti-Mustern.Antworten:
Das von Esailija geprägte verzögerte Antimuster (jetzt explizit konstruiertes Anti-Muster) ist ein weit verbreitetes Anti-Muster-Volk, das neu in Versprechungen ist. Ich habe es selbst gemacht, als ich Versprechen zum ersten Mal verwendet habe. Das Problem mit dem obigen Code ist, dass die Tatsache, die Kette verspricht, nicht ausgenutzt wird.
Versprechen können verkettet werden
.then
und Sie können Versprechen direkt zurückgeben. Ihr Code ingetStuffDone
kann wie folgt umgeschrieben werden:Bei Versprechungen geht es darum, asynchronen Code lesbarer zu machen und sich wie synchroner Code zu verhalten, ohne diese Tatsache zu verbergen. Versprechen stellen eine Abstraktion über einen Wert einer einmaligen Operation dar, sie abstrahieren den Begriff einer Aussage oder eines Ausdrucks in einer Programmiersprache.
Sie sollten verzögerte Objekte nur verwenden, wenn Sie eine API in Versprechen konvertieren und dies nicht automatisch tun können oder wenn Sie Aggregationsfunktionen schreiben, die auf diese Weise einfacher ausgedrückt werden.
Zitat Esailija:
quelle
.defer()
API in den neueren (und sicheren) Versprechenskonstruktor verworfen, sie hat den Gedanken, Versprechungen zu konstruieren, nicht (in keiner Weise) missbilligt :)Was stimmt damit nicht?
Du Glückspilz. Leider ist dies wahrscheinlich nicht der Fall, da Sie wahrscheinlich einen Randfall vergessen haben. In mehr als der Hälfte der Fälle, die ich gesehen habe, hat der Autor vergessen, sich um den Fehlerbehandler zu kümmern:
Wenn das andere Versprechen abgelehnt wird, geschieht dies unbemerkt, anstatt an das neue Versprechen weitergegeben zu werden (wo es behandelt wird) - und das neue Versprechen bleibt für immer ausstehend, was zu Undichtigkeiten führen kann.
Dasselbe passiert, wenn Ihr Rückrufcode einen Fehler verursacht - z. B. wenn
result
keine vorhanden istproperty
und eine Ausnahme ausgelöst wird. Das würde unbehandelt bleiben und das neue Versprechen ungelöst lassen.Im Gegensatz dazu
.then()
kümmert sich die Verwendung automatisch um beide Szenarien und lehnt das neue Versprechen ab, wenn ein Fehler auftritt:Das verzögerte Antimuster ist nicht nur umständlich, sondern auch fehleranfällig . Die Verwendung
.then()
zur Verkettung ist viel sicherer."Ja wirklich?" Gut. Dies ist jedoch sehr detailliert und umfangreich, insbesondere wenn Sie eine Versprechensbibliothek verwenden, die andere Funktionen wie Stornierung oder Nachrichtenübermittlung unterstützt. Oder vielleicht wird es in Zukunft so sein, oder Sie möchten Ihre Bibliothek gegen eine bessere austauschen? Sie möchten Ihren Code dafür nicht neu schreiben.
Die Methoden (
then
) der Bibliotheken unterstützen nicht nur alle Funktionen von Haus aus, sondern verfügen möglicherweise auch über bestimmte Optimierungen. Wenn Sie sie verwenden, wird Ihr Code wahrscheinlich schneller oder kann zumindest durch zukünftige Überarbeitungen der Bibliothek optimiert werden.Wie vermeide ich das?
Wenn Sie also manuell ein
Promise
oderDeferred
bereits vorhandene Versprechen erstellen , überprüfen Sie zuerst die Bibliotheks-API . Das verzögerte Antimuster wird oft von Menschen angewendet, die Versprechen [nur] als Beobachtermuster betrachten - aber Versprechen sind mehr als Rückrufe : Sie sollen zusammensetzbar sein. Jede anständige Bibliothek verfügt über viele benutzerfreundliche Funktionen für die Zusammenstellung von Versprechungen auf jede denkbare Weise, die sich um all die einfachen Dinge kümmern, mit denen Sie sich nicht befassen möchten.Wenn Sie festgestellt haben, dass Sie einige Versprechen auf eine neue Art und Weise verfassen müssen, die von einer vorhandenen Hilfsfunktion nicht unterstützt wird, sollte das Schreiben einer eigenen Funktion mit unvermeidbaren Verzögerungen Ihre letzte Option sein. Wechseln Sie zu einer funktionsfähigeren Bibliothek und / oder melden Sie einen Fehler in Ihrer aktuellen Bibliothek. Der Betreuer sollte in der Lage sein, die Zusammensetzung aus vorhandenen Funktionen abzuleiten, eine neue Hilfsfunktion für Sie zu implementieren und / oder dabei zu helfen, die zu behandelnden Randfälle zu identifizieren.
quelle
setTimeout
, bei der der Konstruktor verwendet werden könnte, aber nicht als "Versprechungskonstruktor anitpattern" betrachtet wird?setTimeout
" ist, sondern " die FunktionsetTimeout
selbst ".setTimeout
"ist, sondern" die FunktionsetTimeout
selbst "." Kann man beschreiben, mit Unterschieden in Verbindung bringen, zwischen den beiden?setTimeout
sich deutlich von der FunktionsetTimeout
selbst , nicht wahr ?