链式承诺不会传递拒绝

Jor*_*dan 32 javascript dojo node.js promise deferred

我有一个问题,理解为什么拒绝不通过承诺链传递,我希望有人能够帮助我理解为什么.对我而言,将功能附加到承诺链意味着我依赖于原始承诺的意图.这很难解释,所以让我先展示一下我的问题的代码示例.(注意:此示例使用Node和延迟节点模块.我使用Dojo 1.8.3进行了测试并得到了相同的结果)

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());
Run Code Online (Sandbox Code Playgroud)

运行此操作的结果是此输出:

promise1 rejected
promise2 resolved
promise3 resolved
Run Code Online (Sandbox Code Playgroud)

好的,对我来说,这个结果没有意义.通过附加到这个承诺链,每个意味着它意味着它将取决于d1的成功解决和结果传递到链.如果promise1中的promise没有收到wins值,而是在其错误处理程序中得到一个错误的值,那么链中的下一个promise怎么可能调用其成功函数?它无法将有意义的值传递给下一个promise,因为它本身并没有获得值.

我可以用不同的方式描述我在想的是:有三个人,John,Ginger和Bob.约翰拥有一个小部件商店.姜进入他的商店,要求一袋各种颜色的小部件.他没有库存,所以他向他的经销商发送请求将他们运到他手中.与此同时,他给了Ginger一张雨检查,说他欠了她一袋小工具.Bob发现Ginger正在获取小部件并要求他在完成这些小部件后获得蓝色小部件.她同意并给了他一张纸条,说明她会.现在,约翰的经销商找不到他们的供应中的任何小部件,制造商也不再制作它们,所以他们告诉约翰,然后通知姜,她无法获得小部件.Bob怎么能在没有得到任何东西的情况下从Ginger获得蓝色小部件?

我在这个问题上的第三个更现实的观点是这个.假设我有两个我想要更新到数据库的值.一个是依赖于另一个的id,但是在我已经将它插入数据库并获得结果之前我无法获得id.最重要的是,第一个插入依赖于来自数据库的查询.数据库调用返回promises,我用它将两个调用链接成一个序列.

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 });
Run Code Online (Sandbox Code Playgroud)

现在,在这种情况下,如果db.query失败,它将调用第一个的错误函数.但随后它将称之为下一个承诺的成功功能.虽然该承诺期望第一个值的结果,但它将从其错误处理函数中获取错误消息.

所以,我的问题是,如果我必须在成功函数中测试错误,为什么我会有错误处理函数?

对不起这个长度.我只是不知道如何以另一种方式解释它.

更新和更正

(注意:我删除了我曾经对某些评论做出的回复.所以,如果有人对我的回复发表评论,那么他们的评论可能看起来不合时宜,因为我删除了它.对不起,我试图尽量缩短.)

谢谢大家的回复.我想首先向所有人道歉,因为我的问题写得太差了,特别是我的伪代码.试图保持简短,我有点过于激进了.

感谢Bergi的回复,我想我在逻辑中发现了错误.我想我可能忽略了导致我遇到问题的另一个问题.这可能导致承诺链的工作方式与我认为的不同.我仍在测试我的代码的不同元素,所以我甚至无法形成一个正确的问题,看看我做错了什么.我确实想要更新你们所有人,谢谢你的帮助.

Ber*_*rgi 26

对我来说,这个结果没有意义.通过附加到这个承诺链,每个意味着它意味着它将取决于d1的成功解决和结果传递到链

不,你所描述的不是一个链条,而只是将所有的回调附加到d1.然而,如果你想连接一些东西then,结果promise2取决于回调的处理方式promise1 then处理方式.

文档说明:

返回回调结果的新承诺.

.then方法通常根据Promises/A规范(或更严格的Promsises/A + one)来考虑.这意味着回调shell返回将被同化成为解析的promise promise2,如果没有成功/错误处理程序,相应的结果将直接传递给promise2- 所以你可以简单地省略处理程序来传播错误.

然而,如果处理错误,结果promise2将被视为固定,并将使用该值来实现.如果您不想这样,则必须重新throw发生错误,就像在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());
Run Code Online (Sandbox Code Playgroud)

Bob怎么能在没有得到任何东西的情况下从Ginger获得蓝色小部件?

他不应该.如果没有错误处理程序,他只会感知消息((来自分销商)来自约翰)来自Ginger)没有小部件.然而,如果Ginger为这种情况设置了一个错误处理程序,她仍然可以实现她的承诺,如果John或他的经销商没有留下蓝色的那个,就可以给自己一个绿色的小屋给Bob一个小部件.

要将错误回调转换为metapher,return err从处理程序就像是说"如果没有小部件,只要告诉他没有剩下的小部件 - 它就像所需的小部件一样好".

在数据库情况下,如果db.query失败,它将调用第一个的err函数

...这意味着错误在那里处理.如果您不这样做,只需省略错误回调.顺便说一句,你的成功回调并不是return他们所创造的承诺,所以他们似乎毫无用处.正确的是:

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();
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

或者,因为您不需要闭包来访问先前回调的结果值,即使:

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);
Run Code Online (Sandbox Code Playgroud)

  • 当使用带有$ q的angularJS时,throw关键字将替换为$ q.reject(err). (3认同)
  • 为了清理@Toilal的评论,'throw`的*首选*替换是`return $ q.reject(err)`.我相信`throw`仍然有效; 它只是慢得多. (3认同)