2016-07-28 16 views
1

Ich beginne mit E6 Versprechen. Ich mag sie sehr, aber es gibt ein entscheidendes Konzept zur Fehlerbehandlung, das ich nicht verstehe und das ich gerne etwas genauer erklären würde.ES6 Versprechen Fehler sprudeln nicht wie erwartet

Lassen Sie uns die folgende einfache Funktion übernehmen, die ein Versprechen zurückgibt:

function promiseString(str, timeout, doResolve) { 
     return new Promise((resolve, reject) => { 
      setTimeout(() => { 
       if (doResolve) { 
        resolve(str); 
       } else { 
        reject(new Error("Rejecting " + str)); 
       } 
      }, timeout); 
     }); 
    } 

Es ist ziemlich einfach ist, gibt nur ein Versprechen für die Zeichenfolge, die an sie übergeben wurde, und die Ursachen, die gelöst oder abgelehnt versprechen werden (basierend auf dem dritten Argument) in "Timeout" Millisekunden.

Ich kann dies vollständig verbrauchen wie erwartet wie folgt:

  promiseString("One", 100, true) 
       .then((str) => { console.log("First then is " + str); return promiseString(str + " two", 100, true); }) 
       .then((str) => { console.log("Second then is " + str); return promiseString(str + " three", 100, true); }) 
       .then((str) => console.log(str)) 
       .catch((err) => console.error(err)); 

Wenn auf von „true“ auf „false“ in einem der Anrufe in dieser Kette das dritte Argument ändern, wird mein Fehler gefangen wie erwartet und sende an console.error().

Doch jetzt stellen Sie sich die folgenden (ähnlich albern) Funktion für ein vielversprechendes Objekt konstruieren:

function DoublePromiser(str1, str2, doResolve) { 
     this.promise = new Promise((resolve, reject) => { 
      promiseString(str1, 100, doResolve) 
       .then((s1) => promiseString(s1 + str2, 100, doResolve)) 
       .then((s2) => resolve(s2)); 
     }); 
    } 

jetzt Stellen Sie sich vor, dass ich diesen Code verbrauchen wie folgt, mit allem, was zu lösen und nichts Ablehnung (doResolve wird auf true):

  var dp = new DoublePromiser("Big", "Promise", true); 
      dp.promise 
       .then((s) => console.log("DoublePromise: " + s)) 
       .catch((err)=>console.log("I did catch: ", err.message)); 

Wie zu erwarten, sehe ich folgend in der Konsole:

DoublePromise: BigPromise

aber jetzt habe ich den verzehrenden Code ändern, das Setzen von doResolve auf „false“ (was bewirkt, dass mein Versprechen Routine ablehnen):

  var dp = new DoublePromiser("Big", "Promise", false); 
      dp.promise 
       .then((s) => console.log("DoublePromise: " + s)) 
       .catch((err)=>console.log("I did catch: ", err.message)); 

Wegen meines Verständnisses davon, wie Fehler sollten „sprudeln“, ich würde erwarten, Die Konsole loggt sich wie folgt ein:

I did catch: Rejecting Big

Aber das tut es nicht. Stattdessen zeigt die Konsole eine nicht erfasste Fehler:

Uncaught (in promise) Error: Rejecting Big

ich nur bekommen, was ich erwarten (und Lust), wenn ich einen Haken an dem Ende der Kette in der DoublePromiser hinzuzufügen, wie folgt aus:

function DoublePromiser(str1, str2, doResolve) { 
     this.promise = new Promise((resolve, reject) => { 
      promiseString(str1, 100, doResolve) 
       .then((s1) => promiseString(s1 + str2, 100, doResolve)) 
       .then((s2) => resolve(s2)) 
       .catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK 
     }); 
    } 

Jetzt bekomme ich was ich erwarte, der Fehler ist nicht aufgefallen. Aber das scheint der ganzen Idee zu widersprechen, dass Fehler auftauchen, und es scheint seltsam, einen Fehler zu finden, nur um den gleichen Fehler zurückzuweisen.

Fehle ich eine Möglichkeit, dies einfach zur Arbeit zu bringen?

Fehle ich ein grundlegendes Konzept?

+0

Diese 100% theoretischen Fragen mit erfundenem Code, die kein wirkliches Problem darstellen, funktionieren beim Stack-Overflow nur schlecht. – jfriend00

+0

Auch Sie verwenden die Verheißung Konstruktor Anti-Muster: https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns – jfriend00

+0

@estus - Ich habe ihren Titel bearbeitet. – jfriend00

Antwort

3

Sie verwenden einen Verhinderungskonstruktor Anti-Pattern. Wickeln Sie ein bestehendes Versprechen nicht in ein anderes Versprechen ein, das Sie selbst machen, denn das bringt Ihnen viel zusätzliche Arbeit, damit die Dinge richtig funktionieren und da die meisten Leute diese zusätzliche Arbeit nicht richtig machen, ist sie auch sehr anfällig für Programmierfehler. Gib einfach das Versprechen zurück, das du bereits hast.

ändern diese:

function DoublePromiser(str1, str2, doResolve) { 
    this.promise = new Promise((resolve, reject) => { 
     promiseString(str1, 100, doResolve) 
      .then((s1) => promiseString(s1 + str2, 100, doResolve)) 
      .then((s2) => resolve(s2)) 
      .catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK 
    }); 
} 

dazu:

function DoublePromiser(str1, str2, doResolve) { 
    return promiseString(str1, 100, doResolve) 
     .then((s1) => promiseString(s1 + str2, 100, doResolve)); 
} 

Und dann benutzen Sie es einfach als eine Funktion:

DoublePromiser("Big", "Promise", false).then(...); 

Recap: Sie fast immer ays möchten innere Versprechungen aus Handlern zurückgeben, da dies es ermöglicht, verschachtelte Fehler nach oben zu propagieren und auch asynchrone Vorgänge/Ketten korrekt zu verketten.

Und Sie wollen vermeiden, neue Versprechen um bestehende Versprechen fast immer zu wickeln, weil Sie nur die bestehenden Versprechen verketten und/oder zurückgeben können, die Sie bereits haben.

Beachten Sie auch, dass wenn Sie ein .catch() tun, das wird „Griff“ ein abgelehnt Versprechen und gibt eine neue nicht abgelehnt Versprechen, von dort mit dem Versprechen Kette fortsetzt, es sei denn, in der .catch() Handler Sie einen abgelehnten Versprechen oder throw zurückkehren eine Ausnahme. Also, das:

p.catch((err) => console.log(err)).then(() => console.log("chain continues")) 

wird gerne tut beiden console.log() Aussagen, weil die .catch() „behandelt“ das Versprechen, so das Versprechen Kette glücklich weiter.


Wie ich in meinem früheren Kommentaren gesagt, diese 100% der theoretischen Diskussionen sind schwer zu genau bekommen, was Sie wirklich erreichen wollen (müssen wir erraten, was das eigentliche Problem ist) ohne 20-seitige Anleitung, wie man verspricht Arbeit, die viel abdeckt. Es ist viel besser, wenn Sie ein Problem der realen Welt posten, das Sie mit dieser Technik lösen wollen, und wir können Ihnen den besten Weg zeigen, dies in ein paar Zeilen Code und ein paar erklärenden Abschnitten zu erklären.

+0

Vielen Dank für Ihre Arbeit. Ich werde morgen deine Antwort durcharbeiten. Die "real world" -Version ist so groß und skurril, dass es schwer ist, sie für StackOverflow prägnant zu beschreiben. Es hat mit dem Erstellen eines Caching-Systems mit IndexedDb für ein SAAS-System zu tun, aber ein ziemlich kompliziertes Caching-System. Ich habe ziemlich viel Zeit damit verbracht, das Problem der "echten Welt" mit diesem "falschen Welt" -Ausschnitt zu verwischen. Unser aktuelles Design erfordert, dass wir ein Objekt über einen Konstruktor erstellen, aber ich werde versuchen, Ihre Konzepte nicht zu den nächsten Versprechen zu verwenden und zu sehen, wo ich hinkomme. –

+0

Und .... Deshalb liebe ich StackOverflow. Nachdem ich viele Spec-Dokumente und Tutorials gelesen hatte und diese "meistens" richtig gemacht hatte, fiel der Penny schließlich auf das "Anti-Pattern" und die Nesting. Und es funktioniert gut, das Gleiche in einem Konstruktor zu tun. Perfekt. Vielen Dank. –

+0

@StephanGolux - Großartig. Das Problem mit einem Konstruktor ist, dass eine Verheißung nicht zurückgegeben werden kann. Aber Sie können tun, was Sie getan haben, was die Versprechen in Instanz Daten halten und erreichen, um es nach dem Aufruf des Konstruktors zu bekommen.Obwohl mir das seltsam vorkommt, aber vielleicht, weil Sie keinen anderen Zweck angeben, als ob es ein Objekt/Konstruktor wäre. – jfriend00