一尘不染

处理承诺链中的多个渔获

node.js

我对诺言仍然相当陌生,并且目前正在使用蓝鸟,但是在我不确定如何最好地处理它的情况下。

因此,例如,我在快速应用程序中有一个promise链,如下所示:

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

任何帮助都会很棒。


阅读 241

收藏
2020-07-07

共1个答案

一尘不染

此行为完全类似于同步抛出:

try{
    throw new Error();
} catch(e){
    // handle
} 
// this code will run, since you recovered from the error!

.catch是能够从错误中恢复的一半。可能需要重新抛出信号以指示状态仍然是错误:

try{
    throw new Error();
} catch(e){
    // handle
    throw e; // or a wrapper over e so we know it wasn't handled
} 
// this code will not run

但是,仅此一种方法无法解决您的问题,因为以后的处理程序会捕获该错误。真正的问题是,广义的“ HANDLE
ANYTHING”错误处理程序通常是一种不好的做法,在其他编程语言和生态系统中却极少使用。因此,蓝鸟提供了类型化和谓语捕获。

附加的优点是您的业务逻辑根本不需要(也不应该)知道请求/响应周期。决定客户端获取哪种HTTP状态和错误不是查询的责任,以后随着应用的增长,您可能希望将业务逻辑(如何查询数据库以及如何处理数据)与发送给客户端的内容分开(什么http状态代码,什么文本和什么响应)。

这就是我编写您的代码的方式。

首先,我将.Query抛出一个NoSuchAccountError,将其从Promise.OperationalErrorBluebird已经提供的子类化。如果您不确定如何将错误归类,请告诉我。

我还要为其子类化AuthenticationError,然后执行类似的操作:

function changePassword(queryDataEtc){ 
    return repository.Query(getAccountByIdQuery)
                     .then(convertDocumentToModel)
                     .then(verifyOldPassword)
                     .then(changePassword);
}

如您所见-它非常干净,您可以阅读文本,就像使用说明书一样,了解过程中发生的情况。它也与请求/响应分开。

现在,我将从路由处理程序中这样调用它:

 changePassword(params)
 .catch(NoSuchAccountError, function(e){
     res.status(404).send({ error: "No account found with this Id" });
 }).catch(AuthenticationError, function(e){
     res.status(406).send({ OldPassword: error });
 }).error(function(e){ // catches any remaining operational errors
     res.status(500).send({ error: "Unable to change password" });
 }).catch(function(e){
     res.status(500).send({ error: "Unknown internal server error" });
 });

这样,逻辑就全部集中在一个地方,而如何处理客户端错误的决定就全部集中在一个地方,并且它们不会彼此混乱。

2020-07-07