Absagen werden nicht in verketteten Versprechen propagiert
P粉193307465
P粉193307465 2023-10-23 17:50:47
0
2
2868

Ich kann nicht verstehen, warum die Ablehnung nicht durch die Versprechenskette weitergeleitet wird. Ich hoffe, jemand kann mir helfen, den Grund zu verstehen. Für mich bedeutet das Anhängen einer Funktion an eine Folge von Versprechen, dass ich mich darauf verlasse, dass die Absicht des ursprünglichen Versprechens erfüllt wird. Das ist schwer zu erklären, deshalb möchte ich zunächst ein Codebeispiel meines Problems zeigen. (Hinweis: In diesem Beispiel werden Node und das verzögerte Knotenmodul verwendet. Ich habe dies mit Dojo 1.8.3 getestet und die gleichen Ergebnisse erhalten.)

var d = require("deferred");

var d1 = d();

var promise1 = d1.promise.then(
    function(wins) { console.log('promise1 resolved'); return wins;},
    function(err) { console.log('promise1 rejected'); return err;});
var promise2 = promise1.then(
    function(wins) { console.log('promise2 resolved'); return wins;},
    function(err) { console.log('promise2 rejected'); return err;});
var promise3 = promise2.then(
    function(wins) { console.log('promise3 resolved'); return wins;},
    function(err) { console.log('promise3 rejected'); return err;});
d1.reject(new Error());

Das Ergebnis dieser Ausführung ist diese Ausgabe:

promise1 rejected
promise2 resolved
promise3 resolved

Nun, für mich ergibt dieses Ergebnis keinen Sinn. Durch das Anhängen an diese Promise-Kette impliziert jedes dann die Absicht, dass es von der erfolgreichen Auflösung von d1 und dem Ergebnis abhängt, das entlang der Kette weitergeleitet wird. Wenn das Versprechen in Versprechen1 keinen Wins-Wert, sondern einen Err-Wert in seinem Fehlerhandler erhält, wie kann das nächste Versprechen in der Kette dann seine Erfolgsfunktion aufrufen? Es kann kein sinnvoller Wert an das nächste Versprechen übergeben werden, da es den Wert selbst nicht erhält.

Ich kann meine Idee auch anders beschreiben: Es sind drei Leute: John, Ginger und Bob. John besitzt einen Widget-Shop. Ginger betrat seinen Laden und bat um eine Tüte mit Gadgets in verschiedenen Farben. Da er sie nicht vorrätig hatte, schickte er eine Anfrage an seinen Händler, damit er sie sich zuschicken lassen könne. Unterdessen gibt er Ginger einen Regenscheck und sagt, dass er ihr die Tüte mit den Widgets schuldet. Bob sieht, wie Ginger die Widgets bekommt und bittet ihn, das blaue Widget zu holen, wenn sie damit fertig ist. Sie stimmte zu und gab ihm eine Nachricht, dass sie zustimmen würde. Jetzt kann Johns Händler keine Widgets in seinem Angebot finden und der Hersteller stellt die Widgets nicht mehr her. Daher benachrichtigt er John, der wiederum Ginger darüber informiert, dass sie die Widgets nicht erhalten kann. Wie kann Bob das blaue Widget von Ginger bekommen, wenn er selbst nichts bekommt?

Meine dritte, realistischere Perspektive zu diesem Thema ist diese. Nehmen wir an, ich habe zwei Werte, die ich in der Datenbank aktualisieren möchte. Das eine hängt von der ID des anderen ab, aber ich kann die ID erst erhalten, wenn ich sie in die Datenbank einfüge und das Ergebnis erhalte. Darüber hinaus hängt die erste Einfügung von der Datenbankabfrage ab. Das vom Datenbankaufruf zurückgegebene Versprechen verwende ich, um die beiden Aufrufe zu einer Sequenz zu verketten.

var promise = db.query({parent_id: value});
promise.then(function(query_result) {
    var first_value = {
        parent_id: query_result[0].parent_id
    }
    var promise = db.put(first_value);
    promise.then(function(first_value_result) {
        var second_value = {
            reference_to_first_value_id: first_value_result.id
        }
        var promise = db.put(second_value);
        promise.then(function(second_value_result) {
            values_successfully_entered();
        }, function(err) { return err });
    }, function(err) { return err });
}, function(err) { return err });

Wenn in diesem Fall db.query fehlschlägt, ruft es die erste und dann die err-Funktion auf. Aber dann ruft es die Erfolgsfunktion des nächsten Versprechens auf. Obwohl dieses Versprechen das Ergebnis des ersten Werts erwartet, erhält es von seiner Fehlerbehandlungsfunktion eine Fehlermeldung.

Meine Frage ist also: Wenn ich in der Erfolgsfunktion auf Fehler testen muss, warum habe ich dann eine Fehlerbehandlungsfunktion?

Leider ist dieser Beitrag zu lang. Ich weiß einfach nicht, wie ich es anders erklären soll.

Aktualisierungen und Korrekturen

(Hinweis: Ich habe eine Antwort gelöscht, die ich auf einige Kommentare gegeben hatte. Wenn also jemand meine Antwort kommentiert hat, erscheint sein Kommentar möglicherweise aus dem Kontext gerissen, nachdem ich ihn gelöscht habe. Tut mir leid, ich versuche, ihn so kurz wie möglich zu halten möglich)

Vielen Dank an alle für eure Antworten. Zunächst möchte ich mich bei allen dafür entschuldigen, dass meine Frage schlecht geschrieben war, insbesondere mein Pseudocode. Ich war etwas zu aggressiv und habe versucht, es kurz zu halten.

Danke für die Antwort Bergi, ich glaube, ich habe den Fehler in meiner Logik gefunden. Ich glaube, ich übersehe möglicherweise ein anderes Problem, das die Probleme verursacht, die ich habe. Dies kann dazu führen, dass die Versprechenskette anders funktioniert, als ich dachte. Ich teste immer noch verschiedene Elemente des Codes, daher kann ich nicht einmal eine richtige Frage formulieren, um zu sehen, was ich falsch mache. Ich möchte jedoch alle über die Situation auf dem Laufenden halten und danke Ihnen für Ihre Hilfe.

P粉193307465
P粉193307465

Antworte allen(2)
P粉155710425

@Jordan 首先,正如评论者指出的,当使用延迟库时,您的第一个示例肯定会产生您期望的结果:

promise1 rejected
promise2 rejected
promise3 rejected

其次,即使它会产生您建议的输出,它也不会影响第二个代码段的执行流程,这有点不同,更像是:

promise.then(function(first_value) {
    console.log('promise1 resolved');
    var promise = db.put(first_value);
    promise.then(function (second_value) {
         console.log('promise2 resolved');
         var promise = db.put(second_value);
         promise.then(
             function (wins) { console.log('promise3 resolved'); },
             function (err) { console.log('promise3 rejected'); return err; });
    }, function (err) { console.log('promise2 rejected'); return err;});
}, function (err) { console.log('promise1 rejected'); return err});

并且,如果第一个承诺被拒绝,只会输出:

promise1 rejected

然而(到达最有趣的部分)即使延迟库肯定返回 3 x returned,大多数其他承诺库将返回 1 x returned, 2 x 已解决(这导致假设您通过使用其他一些 Promise 库获得了这些结果)。

另外令人困惑的是,其他库的行为更加正确。让我解释一下。

在同步世界中,“承诺拒绝”的对应部分是抛出。因此从语义上讲,同步中的异步 deferred.reject(new Error()) 等于 throw new Error()。 在您的示例中,您不会在同步回调中​​抛出错误,您只是返回它们,因此您切换到成功流程,其中错误是成功值。为了确保拒绝进一步通过,您需要重新抛出错误:

function (err) { console.log('promise1 rejected'); throw err; });

现在的问题是,为什么延迟库将返回的错误视为拒绝?

原因是延迟工作中的拒绝有点不同。在 deferred lib 中,规则是:当出现错误实例时,promise 会被拒绝,因此即使你执行 deferred.resolve(new Error()) 它也会起作用如 deferred.reject(new Error()) ,如果你尝试执行 deferred.reject(notAnError) ,它会抛出一个异常,表示该 Promise 只能被拒绝有错误的实例。这清楚地表明了为什么从 then 回调返回的错误拒绝了承诺。

延迟逻辑背后有一些有效的推理,但它仍然与 JavaScript 中 throw 的工作方式不符,因此,此行为计划在延迟的 v0.7 版本中进行更改。

简短摘要:

为了避免混乱和意外结果,只需遵循良好实践规则:

  1. 始终拒绝带有错误实例的承诺(遵循同步世界的规则,其中抛出非错误的值被视为不好的做法)。
  2. 通过抛出错误拒绝同步回调(返回错误并不能保证拒绝)。

遵守上述规定,您将在延迟库和其他流行的 Promise 库中获得一致且预期的结果。

P粉376738875

没有。您所描述的不是一个链,而只是将所有回调附加到d1。然而,如果您想使用 then 链接某些内容,promise2 的结果取决于 promise1 的分辨率以及 promise1 的分辨率以及 然后回调处理了它。

文档指出:

.then 方法通常根据 Promises 来看待/A 规范(或者更严格的Promsises/A+ )。这意味着回调 shell 返回的 Promise 将被同化为 Promise2 的解析,如果没有成功/错误处理程序,相应的结果将直接传递给 Promise2 code> - 因此您可以简单地省略处理程序来传播错误。

但是,如果错误被处理,则生成的 promise2 被视为已修复,并将用该值来实现。如果您不希望出现这种情况,则必须重新抛出错误,就像在 try-catch 子句中一样。或者,您可以从处理程序返回一个(待)拒绝的承诺。不确定 Dojo 的拒绝方式是什么,但是:

var d1 = d();

var promise1 = d1.promise.then(
    function(wins) { console.log('promise1 resolved'); return wins;},
    function(err) { console.log('promise1 rejected'); throw err;});
var promise2 = promise1.then(
    function(wins) { console.log('promise2 resolved'); return wins;},
    function(err) { console.log('promise2 rejected'); throw err;});
var promise3 = promise2.then(
    function(wins) { console.log('promise3 resolved'); return wins;},
    function(err) { console.log('promise3 rejected'); throw err;});
d1.reject(new Error());

他不应该能够。如果没有错误处理程序,他只会感知到没有剩余小部件的消息(((来自约翰)来自 Ginger)。然而,如果金格为这种情况设置了一个错误处理程序,如果约翰或他的经销商没有剩下蓝色的小部件,她仍然可以履行她的承诺,从她自己的小屋里给鲍勃一个小部件,给他一个绿色的小部件。

要将错误回调转换为元,从处理程序返回错误就像说“如果没有留下任何小部件,只需给他一个注释,即没有留下任何小部件 - 这是与所需的小部件一样好”。

...这意味着错误已在那里处理。如果您不这样做,只需省略错误回调即可。顺便说一句,您的成功回调不会返回它们正在创建的承诺,因此它们似乎毫无用处。正确的是:

var promise = db.query({parent_id: value});
promise.then(function(query_result) {
    var first_value = {
        parent_id: query_result[0].parent_id
    }
    var promise = db.put(first_value);
    return promise.then(function(first_value_result) {
        var second_value = {
            reference_to_first_value_id: first_value_result.id
        }
        var promise = db.put(second_value);
        return promise.then(function(second_value_result) {
            return values_successfully_entered();
        });
    });
});

或者,由于您不需要闭包来访问先前回调的结果值,甚至:

db.query({parent_id: value}).then(function(query_result) {
    return db.put({
        parent_id: query_result[0].parent_id
    });
}).then(function(first_value_result) {
    return db.put({
        reference_to_first_value_id: first_value_result.id
    });
}.then(values_successfully_entered);
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage