为了账号安全,请及时绑定邮箱和手机立即绑定

处理承诺链中的多个渔获

/ 猿问

处理承诺链中的多个渔获

慕后森 2019-10-15 14:24:22

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


因此,举例来说,我在Express应用程序中有一个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。


任何帮助都会很棒。



查看完整描述

3 回答

?
守候你守候我

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


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" });

 });

这样,逻辑就全部集中在一个地方,而如何为客户处理错误的决定就都集中在一个地方,而且它们不会相互干扰。


查看完整回答
反对 回复 2019-10-15
?
LEATH

.catch就像try-catch语句一样工作,这意味着最后只需要一个捕获即可:


repository.Query(getAccountByIdQuery)

        .then(convertDocumentToModel)

        .then(verifyOldPassword)

        .then(changePassword)

        .then(function(){

            res.status(200).send();

        })

        .catch(function(error) {

            if (/*see if error is not found error*/) {

                res.status(404).send({ error: "No account found with this Id" });

            } else if (/*see if error is verification error*/) {

                res.status(406).send({ OldPassword: error });

            } else {

                console.log(error);

                res.status(500).send({ error: "Unable to change password" });

            }

        });


查看完整回答
反对 回复 2019-10-15
?
HUWWW

我想知道是否存在一种方法可以根据错误以某种方式强制链条停止在某个点


不可以。除非您抛出一个冒泡直到结束的异常,否则您无法真正“终止”一条链。有关如何执行此操作的信息,请参见本杰明·格伦鲍姆(Benjamin Gruenbaum)的答案。


他的模式的派生将不是区分错误类型,而是使用具有statusCode和body字段的错误,这些错误和字段可以从单个通用.catch处理程序发送。根据您的应用程序结构,他的解决方案可能会更干净。


或者是否有更好的方法来构造它以获得某种形式的分支行为


是的,您可以使用promises进行分支。但是,这意味着离开链并“返回”嵌套-就像您在嵌套的if-else或try-catch语句中所做的那样:


repository.Query(getAccountByIdQuery)

.then(function(account) {

    return convertDocumentToModel(account)

    .then(verifyOldPassword)

    .then(function(verification) {

        return changePassword(verification)

        .then(function() {

            res.status(200).send();

        })

    }, function(verificationError) {

        res.status(406).send({ OldPassword: error });

    })

}, function(accountError){

    res.status(404).send({ error: "No account found with this Id" });

})

.catch(function(error){

    console.log(error);

    res.status(500).send({ error: "Unable to change password" });

});


查看完整回答
反对 回复 2019-10-15

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信