我仍然是相当新的承诺,目前正在使用蓝鸟,但我有一个场景,我不太确定如何最好地处理它 .
例如,我在快递应用程序中有一个承诺链,如下所示:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
所以我追求的行为是:
-
通过Id获取帐户
-
如果此时有拒绝,则弹出并返回错误
-
如果没有错误,则将文档转换回模型
-
使用数据库文档验证密码
-
如果密码不匹配则弹出并返回不同的错误
-
如果没有错误则更改密码
-
然后返回成功
-
如果出现其他任何问题,请返回500
所以目前捕获似乎并没有停止链接,这是有道理的,所以我想知道是否有办法让我以某种方式迫使链条根据错误在某一点停止,或者是否有更好的方法构造它以获得某种形式的分支行为,因为有一个 if X do Y else Z
的情况 .
任何帮助都会很棒 .
6 回答
.catch
的作用类似于try-catch
语句,这意味着您最后只需要一个捕获:而不是
.then().catch()...
你可以做.then(resolveFunc, rejectFunc)
. 如果您沿途处理事情,这个承诺链会更好 . 以下是我将如何重写它:注意:
if (error != null)
与最近的错误进行交互有点麻烦 .我一直这样做:
你最后留下你的渔获物 . 当它发生在你的链中间时发出错误 .
你的其他功能可能看起来像这样:
我认为Benjamin Gruenbaum's answer above是复杂逻辑序列的最佳解决方案,但这是我对更简单情况的替代方案 . 我只是使用
errorEncountered
标志和return Promise.reject()
来跳过任何后续的then
或catch
语句 . 所以它看起来像这样:如果你有两个以上/捕获对,你应该使用Benjamin Gruenbaum的解决方案 . 但这适用于简单的设置 .
请注意,最终的
catch
只有return;
而不是return Promise.reject();
,因为我们不需要跳过后续的then
,它将被视为未处理的Promise拒绝,Node不喜欢 . 如上所述,最终catch
将返回一个和平解决的Promise .不,你不能真的"end"一个链,除非你抛出一个泡沫直到它结束的例外 . 有关如何操作,请参阅Benjamin Gruenbaum's answer .
他的模式的推导不是要区分错误类型,而是使用具有
statusCode
和body
字段的错误,这些字段可以从单个通用.catch
处理程序发送 . 根据您的应用程序结构,他的解决方案可能更清晰 .是的,你可以做branching with promises . 但是,这意味着将链和"go back"保留为嵌套 - 就像在嵌套的if-else或try-catch语句中一样:
这种行为与同步抛出完全相同:
这是
.catch
的一半 - 能够从错误中恢复 . 可能需要重新抛出信号状态仍然是一个错误:但是,由于错误会被后来的处理程序捕获,因此单独使用此功能不适用于您的情况 . 这里真正的问题是,通用的“HANDLE ANYTHING”错误处理程序通常是一种不好的做法,并且在其他编程语言和生态系统中非常不受欢迎 . 出于这个原因,Bluebird提供了类型和谓词捕获 .
增加的优势是您的业务逻辑根本不(并且不应该)必须知道请求/响应周期 . 查询负责决定客户端获取哪种HTTP状态和错误,以后随着应用程序的增长,您可能希望将业务逻辑(如何查询数据库以及如何处理数据)与发送给客户端的内容分开(什么http状态代码,什么文本和什么响应) .
以下是我编写代码的方法 .
首先,我得
.Query
抛出一个NoSuchAccountError
,我将它从Promise.OperationalError
继承,Bluebird已经提供了它 . 如果您不确定如何将错误子类化,请告诉我 .我另外将它子类化为
AuthenticationError
,然后做类似的事情:正如您所看到的 - 它非常干净,您可以阅读文本,就像过程中发生的事情的说明手册一样 . 它也与请求/响应分开 .
现在,我将从路由处理程序中调用它:
这样,逻辑就在一个地方,如何处理客户端错误的决定都在一个地方,并且它们不会相互混乱 .