我对promises还是相当陌生,目前正在使用bluebird,但是我有一个场景,我不太确定如何最好地处理它.

例如,我在一个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.

任何帮助都会很好.

推荐答案

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

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

然而,在您的情况下,这一点是行不通的,因为错误可能会被稍后的处理程序捕获.这里真正的问题是,一般来说,通用的"处理任何事情"错误处理程序都是一种不好的做法,在其他编程语言和生态系统中极不受欢迎.因此,Bluebird提供类型化和谓词捕获.

另外一个优点是,您的业务逻辑根本不需要(也不应该)知道请求/响应周期.查询不负责决定客户端获得的HTTP状态和错误,稍后随着应用程序的增长,您可能希望将业务逻辑(如何查询数据库和如何处理数据)与发送给客户端的内容(什么HTTP状态代码、什么文本和什么响应)分开.

下面是我如何编写你的代码.

首先,我会得到.Query来抛出一个NoSuchAccountError,我会把它从Promise.OperationalError子类,蓝鸟已经提供.如果您不确定如何对错误进行子分类,请告诉我.

我还将其子类化为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" });
 });

这样,逻辑都在一个地方,如何处理客户机错误的决策都在一个地方,它们不会相互混乱.

Node.js相关问答推荐

AWS Lambda呼叫未登录控制台

如果非SQL函数在事务内部运行失败,PG-Promise事务会回滚吗?

MongoDB的方面查询的Postgres类似功能

使用参考中断Mongoose模型-Node.js

如何从谷歌云中部署的应用程序连接到mongoDB Atlas?

Node-Red Tasmota 错误:连接 ECONNREFUSED 192.168.77.21:1883

PM2 是否需要成为其托管项目的依赖项?

Node.js 连接在查询完成之前终止

Mongodb - 在数组数组中查找()

如何在Node.js的telegraf.js命令中添加参数?

Typescript 正则表达式:过滤器返回空

未捕获的错误: 只能用作 元素的子元素,永远不会直接呈现.请将您的 包裹在

Node.js 上的 CLI 应用程序如何通过 child_process 将选项值作为参数传递给 Shell 命令

为什么 client.on("messageCreate") 的 TextChannel 中缺少 nsfw 属性?

在 Node JS 中使用 url 链接而不是文件路径

在mongodb中只查询整数

分块 WebSocket 传输

Sequelize 基于关联的查找

MongoDB Node findone如何处理没有结果?

如何解决 Socket.io 404(未找到)错误?