Javascript JS承诺:允许错误传播
背景 假设我正在使用NodeJS+Express。我在Express中注册了某些错误处理程序,它们将以适当的方式处理应用程序中可能出现的所有错误 因此,每当需要时,我都会在应用程序中抛出错误。如果有未处理的错误,我会让它传播,直到它到达错误处理程序。然而,当我试图在承诺链中抛出错误时,我遇到了一个问题。以以下为例:Javascript JS承诺:允许错误传播,javascript,express,promise,bluebird,Javascript,Express,Promise,Bluebird,背景 假设我正在使用NodeJS+Express。我在Express中注册了某些错误处理程序,它们将以适当的方式处理应用程序中可能出现的所有错误 因此,每当需要时,我都会在应用程序中抛出错误。如果有未处理的错误,我会让它传播,直到它到达错误处理程序。然而,当我试图在承诺链中抛出错误时,我遇到了一个问题。以以下为例: function find() { // consider this to be a promise from a library such as Bluebird
function find() {
// consider this to be a promise from a library such as Bluebird
return new Promise(function (resolve, reject) {
// ... logic ...
});
}
function controller (req, res) {
// ... omitted ...
find().then(function (result)) {
if (result) {
// let 'res' be the Express response object
res.send("It exists!");
} else {
// let SpecificError be a prototypical subclass of Error
throw new SpecificError("Couldn't find it.");
}
}).catch(function (error) {
// throw the error again, so that the error handler can finish
// the job
throw error;
});
}
虽然我一直期望我重新抛出的错误最终至少会击中通用错误处理程序,但我看到我发送给应用程序的请求挂起,我正在使用的promise库抱怨未处理的拒绝
问题
很简单,我想知道如何通过在我的承诺链中抛出一个错误来解决我似乎在错误地处理我正在创建的拒绝的事实
编辑:有关错误处理程序和控制器
函数(具体)的说明,请参见下面的注释。承诺处理程序是“抛出安全的”。这意味着您在任何承诺处理程序中抛出的任何异常都将被自动捕获并转化为被拒绝的承诺。这就是规范是如何为承诺编写的,以及它们是如何工作的(jQuery承诺的某些版本除外,但这只是因为它们没有遵循规范)
因此,如果您从承诺库中获得“未处理的拒绝”,这是一个有用的警告,告诉您您有一个被拒绝的承诺,而该承诺没有处理程序,因此拒绝被默默忽略,这通常是一个编码错误
事实上,在controller()
函数中,您正好有:
function controller (req, res) {
// ... omitted ...
find().then(function (result)) {
if (result) {
// let 'res' be the Express response object
res.send("It exists!");
} else {
// let SpecificError be a prototypical subclass of Error
throw new SpecificError("Couldn't find it.");
}
}).catch(function (error) {
// throw the error again, so that the error handler can finish
// the job
throw error;
});
}
如果你到了写着“抛出新的SpecificError”
的那一行,那么承诺就会变成被拒绝的承诺。这将导致调用.catch()
处理程序。在该处理程序中,您再次抛出将信守承诺作为拒绝的承诺。因此,最初的承诺以find()。然后(…)
开始,现在将是一个被拒绝的承诺。但是,不再有拒绝处理程序,您也不会从controller()
返回承诺。因此,在这一点上,您有一个未经处理的拒绝承诺。这通常是一个编码错误
对于如何纠正此编码错误,您有多种选择:
.catch()
处理程序中自己处理错误,方法是调用某种类型的错误处理函数,将错误传递给该函数,并将res
参数传递给该函数,然后不抛出错误controller()
函数返回承诺,然后调用该函数的任何代码都可以处理被拒绝的承诺假设您已将函数与以下内容绑定
app.get('/', controller);
function controller (req, res, next) {
find().then(function (result)) {
if (!result) throw new SpecificError("Couldn't find it.");
res.send("It exists!");
}).catch(next);
}
当Express调用控制器时,它已为您提供100%的控制权。如果从控制器
同步抛出异常,则Express很好,并且也会将其视为错误。然而,一旦调用任何异步代码,您就有责任决定如何处理任何错误
对于Express,您有两种选择:
req
和res
,因此您可以捕获错误并向用户发送您想要的任何响应控制器
在Express中实际具有函数(req、res、next)
的函数签名。这是一种非常常见的格式下一个回调。如果在没有参数的情况下调用next()
,这会告诉Express继续处理它拥有的URL处理程序集,试图找到一个将处理请求的处理程序,如果找不到,则返回404
但是,如果您像next(err)
那样将参数传递给next
,Express将跳过剩余的URL处理程序,而不是查找错误处理程序。Express允许您注册自定义处理程序,但如果找不到任何自定义处理程序,它将返回500
那么,在您的示例中,您应该做什么呢?你可能想要像这样的东西
app.get('/', controller);
function controller (req, res, next) {
find().then(function (result)) {
if (!result) throw new SpecificError("Couldn't find it.");
res.send("It exists!");
}).catch(next);
}
这意味着,如果在承诺链内部抛出任何异常,将调用next
函数,Express将接管该函数。您希望它命中的“通用错误处理程序”是什么?如果controller
是一个路由,您应该使用第三个next
参数并执行next(error)
我想您看到了我要做的事情--next(error)
听起来像是正确的答案,如果您演示如何调用controller()
,如果app
是一个快速应用程序,我们会更好地了解您正在做什么以及哪些选项最有意义。通用错误处理程序将类似于app.use(function(err,req,res,next){…})
。controller
函数是路由的处理程序,例如/
。您希望哪个通用错误处理程序被重试错误击中?除了一个抱怨未经处理的拒绝之外,没有其他原因。你肯定会因为解释我出错的原因而得到一张赞成票。由于另一个答案提供了一个明确的解决方案,我将不得不将其标记为解决方案。是的,我认为这是我对如何使用req
、res
和next
的误解。