wake-up-neo.com

Was ist das explizite Versprechen Bau Antipattern und wie vermeide ich es?

Ich habe Code geschrieben, der ungefähr 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 sagte mir, dass dies das " verzögerte Antipattern " oder das "Promise Konstruktor-Antipattern "bzw., was ist schlecht an diesem Code und warum heißt das ein Antipattern ?

459

Das aufgeschobene Antimuster (jetzt explizit konstruiertes Antimuster) geprägt von Esailija ist ein weit verbreitetes Antimuster, das neue Versprechungen machen, die ich selbst gemacht habe, wenn Ich habe zuerst Versprechen benutzt. Das Problem mit dem obigen Code ist, dass die Tatsache, die die Kette verspricht, nicht ausgenutzt wird.

Versprechen können verketten mit .then und Sie können Versprechen direkt zurückgeben. Ihr Code in getStuffDone kann wie folgt umgeschrieben werden:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

In Versprechungen geht es darum, asynchronen Code lesbarer zu machen und sich wie synchroner Code zu verhalten, ohne diese Tatsache zu verbergen. Versprechungen stellen eine Abstraktion über einen Wert einer einmaligen Operation dar, sie abstrahieren den Begriff einer Aussage oder eines Ausdrucks in einer Programmiersprache.

Sie sollten zurückgestellte Objekte nur verwenden, wenn Sie eine API in Versprechen umwandeln und dies nicht automatisch tun können oder wenn Sie Aggregationsfunktionen schreiben, die auf diese Weise einfacher ausgedrückt werden.

Zitiert Esailija:

Dies ist das häufigste Anti-Pattern. Es ist leicht, sich darauf einzulassen, wenn Sie Versprechungen nicht wirklich verstehen und sie als verherrlichte Ereignisemitter oder als Rückrufdienstprogramm betrachten. Lassen Sie uns noch einmal zusammenfassen: In Versprechungen geht es darum, dass asynchroner Code die meisten verlorenen Eigenschaften von synchronem Code beibehält, z. B. flache Einrückungen und einen Ausnahmekanal.

320

Was stimmt damit nicht?

Aber das Muster funktioniert!

Du Glückspilz. Leider ist dies wahrscheinlich nicht der Fall, da Sie wahrscheinlich einen Edge-Fall vergessen haben. In mehr als der Hälfte der Fälle, die ich gesehen habe, hat der Autor vergessen, sich um die Fehlerbehandlung zu kümmern:

return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
        resolve(result.property.example);
    });
})

Wenn das andere Versprechen abgelehnt wird, geschieht dies unbemerkt, anstatt an das neue Versprechen weitergegeben zu werden (wo es gehandhabt würde) - und das neue Versprechen bleibt für immer anhängig, was zu Undichtigkeiten führen kann.

Dasselbe passiert, wenn Ihr Rückrufcode einen Fehler verursacht - z. wenn result kein property hat und eine Ausnahme ausgelöst wird. Das würde ungenutzt bleiben und das neue Versprechen ungelöst lassen.

Im Gegensatz dazu werden bei Verwendung von .then() diese beiden Szenarien automatisch berücksichtigt und das neue Versprechen zurückgewiesen, wenn ein Fehler auftritt:

 return getOtherPromise().then(function(result) {
     return result.property.example;
 })

Das aufgeschobene Antimuster ist nicht nur umständlich, sondern auch fehleranfällig . Die Verwendung von .then() zum Verketten ist viel sicherer.

Aber ich habe alles erledigt!

"Ja wirklich?" Gut. Dies ist jedoch ziemlich detailliert und umfangreich, insbesondere wenn Sie eine Versprechungsbibliothek verwenden, die andere Funktionen wie das Abbrechen oder das Weiterleiten von Nachrichten unterstützt. Oder vielleicht in Zukunft, oder Sie möchten Ihre Bibliothek gegen eine bessere austauschen? Sie werden Ihren Code dafür nicht umschreiben wollen.

Die Methoden der Bibliotheken (then) unterstützen nicht nur nativ alle Funktionen, sondern weisen möglicherweise auch bestimmte Optimierungen auf. Wenn Sie sie verwenden, wird Ihr Code wahrscheinlich schneller oder kann zumindest durch zukünftige Überarbeitungen der Bibliothek optimiert werden.

Wie vermeide ich es?

Wenn Sie also feststellen, dass Sie ein Promise oder Deferred manuell erstellen und bereits vorhandene Versprechen einbeziehen, überprüfen Sie zuerst die Bibliotheks-API . ). Das aufgeschobene Gegenmuster wird häufig 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 erdenkliche Art und Weise und kümmert sich um all die Dinge auf niedriger Ebene, mit denen Sie sich nicht befassen möchten.

Wenn Sie die Notwendigkeit gefunden haben, einige Versprechen auf eine neue Art und Weise zu verfassen, die von einer vorhandenen Hilfsfunktion nicht unterstützt wird, sollten Sie als letzte Option Ihre eigene Funktion mit unvermeidbaren Verzögerungen schreiben. Ziehen Sie in Betracht, zu einer leistungsstärkeren Bibliothek zu wechseln und/oder einen Fehler in Ihrer aktuellen Bibliothek zu melden. Sein Betreuer sollte in der Lage sein, die Komposition aus vorhandenen Funktionen abzuleiten, eine neue Hilfsfunktion für Sie zu implementieren und/oder die Edge-Fälle zu identifizieren, die behandelt werden müssen.

120
Bergi