我对 Promise 还很陌生,目前正在使用 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
但是,仅此方法在您的情况下不起作用,因为错误会被稍后的处理程序捕获。这里真正的问题是,广义的“HANDLE ANYTHING”错误处理程序通常是一种不好的做法,并且在其他编程语言和生态系统中非常不受欢迎。因此,Bluebird 提供类型化和谓词捕获。
另一个优点是您的业务逻辑根本不需要(也不应该)了解请求/响应周期。查询没有责任决定客户端获取哪种 HTTP 状态和错误,稍后随着应用程序的增长,您可能希望将业务逻辑(如何查询数据库以及如何处理数据)与发送给客户端的内容分开(什么http状态代码,什么文本和什么响应)。
这是我编写代码的方式。
首先,我会让 .Query
抛出一个 NoSuchAccountError
,我会从 Bluebird 已经提供的 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" });
});
这样,逻辑就全部集中在一个地方,并且如何向客户端处理错误的决定也集中在一个地方,并且它们不会相互困惑。
关于javascript - 处理 promise 链中的多个捕获,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26470502/