猿问

被束缚的承诺不会被拒绝

被束缚的承诺不会被拒绝

我很难理解为什么拒绝不能通过承诺链传递,我希望有人能帮助我理解其中的原因。对我来说,将功能附加到一系列的承诺中意味着我依赖于最初的承诺来实现它的意图。很难解释,所以让我先给出一个问题的代码示例。(注意:此示例使用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());

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

promise1 rejected
promise2 resolved
promise3 resolved

好吧,对我来说,这个结果没有意义。通过附加到这个承诺链上,每个承诺链都意味着它将依赖于D1的成功解决,并将结果传递到该链中。如果承诺1中的承诺没有接收WINS值,而是在其错误处理程序中获得错误值,那么如何使链中的下一个承诺调用其成功函数?它不可能将有意义的值传递给下一个承诺,因为它本身没有得到一个值。

另一种我可以描述的想法是:有三个人,约翰,金格和鲍勃。约翰拥有一家小玩具店。姜走进他的店里,要了一袋五颜六色的小玩意儿。他没有库存,所以他向他的分销商发出了一份请求,要求把它们运给他。同时,他给了金格一次改天的机会,说他欠她一袋小工具。Bob发现Ginger正在获取这些小部件,并要求在完成这些小部件后获得蓝色小部件。她同意了,并给了他一张纸条,说她会的。现在,John的分销商在他们的产品中找不到任何小部件,制造商也不再生产这些小部件,所以他们通知John,John反过来告诉Ginger她无法获得这些小部件。鲍勃怎么能从金格那里得到一个蓝色的小部件,而她却没有得到任何东西呢?

我对这个问题的第三个更现实的观点是这一点。假设我有两个要更新到数据库的值。一个依赖于另一个的id,但是在我已经将它插入数据库并获得结果之前,我无法获得id。除此之外,第一个INSERT依赖于来自数据库的查询。数据库调用返回承诺,用于将两个调用链接到一个序列中。


现在,在这种情况下,如果db.query失败,它将调用第一个查询的err函数。但是,它会把下一个承诺的成功函数称为“成功函数”。虽然这个承诺是期望第一个值的结果,但是它将从它的错误处理程序函数中得到错误消息。

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

很抱歉这么长时间。我只是不知道怎么用另一种方式来解释

温温酱
浏览 534回答 3
3回答

智慧大石

首先正如评论者所指出的,在使用延迟库时,您的第一个示例肯定会产生您期望的结果: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 rejected,大多数其他承诺库将返回。1 x rejected, 2 x resolved(这会导致假设您通过使用其他承诺库来获得这些结果)。另外,令人困惑的是,其他库的行为更正确。让我解释一下。在同步世界中,“拒绝承诺”的对应词是throw..所以在语义上,异步deferred.reject(new Error())同步等于throw new Error()..在您的示例中,您没有在同步回调中抛出错误,您只是返回它们,因此切换到成功流,错误是成功的值。为了确保拒绝得到进一步通过,您需要重新抛出错误:function (err) { console.log('promise1 rejected'); throw err; });所以现在的问题是,为什么延迟库将返回的错误作为拒绝?原因是,在推迟的情况下,拒绝的工作方式有点不同。在延迟库中,规则是:承诺在被错误实例解析后被拒绝所以即使你这么做deferred.resolve(new Error())它将充当deferred.reject(new Error()),如果你想做deferred.reject(notAnError)它会抛出一个异常,也就是说,只有在错误的情况下才能拒绝承诺。这说明了为什么从then回调拒绝承诺。递延逻辑背后有一些合理的推理,但它仍与如何做到这一点相去甚远。throw在JavaScript中工作,并且由于此行为计划更改版本V0.7的延迟。摘要:为了避免混乱和意想不到的结果,只需遵循良好的实践规则:始终用错误实例拒绝您的承诺(遵循同步世界的规则,其中抛出不是错误的值被认为是错误的做法)。从同步回调中拒绝投掷错误(返回错误不能保证拒绝)。遵循以上所述,您将在延迟库和其他流行的承诺库中获得一致和预期的结果。
随时随地看视频慕课网APP
我要回答