JS Promises:允许传播错误
JS Promises: Allowing Propagation of Errors
背景
假设我正在使用 NodeJS + Express。我在 Express 中注册了某些错误处理程序,它们将以适当的方式处理我的应用程序中可能出现的所有错误。
因此,只要我需要,我就会在我的应用程序中抛出错误。如果有未处理的错误,我让它传播直到它到达错误处理程序。但是,在尝试在承诺链内部抛出错误时,我 运行 遇到了问题。举个例子:
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;
});
}
虽然我一直期待我重新抛出的错误最终至少会命中通用错误处理程序,但我却看到我发送到我的应用程序的请求挂起,以及我正在使用的承诺库抱怨 Unhandled rejection
.
问题
很简单,我想知道如何通过在我的承诺链中抛出错误来解决我似乎错误处理了我正在创建的拒绝这一事实。
编辑:为了澄清错误处理程序和 controller
函数(具体)是什么,请参阅下面的评论。
Promise 处理程序是 "throw safe"。这意味着您在任何 promise 处理程序中抛出的任何异常都将被自动捕获并变成一个被拒绝的 promise。这就是为 promise 编写规范的方式以及它们的工作方式(jQuery promises 的某些版本除外,但这只是因为它们不遵循规范)。
因此,如果您从您的 promise 库中获取 "Unhandled rejection",那将是一个有用的警告,告诉您您有一个被拒绝的 promise,但没有处理程序,因此该拒绝被默默地忽略了通常是编码错误。
而且,实际上在您的 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;
});
}
如果您到达显示 throw new SpecificError
的那一行,那么这会将承诺变成拒绝的承诺。这将导致您的 .catch()
处理程序被调用。在该处理程序中,您再次抛出,这将使承诺保持为被拒绝的承诺。因此,以 find().then(...)
开头的原始承诺现在将成为被拒绝的承诺。但是,没有更多的拒绝处理程序,您也没有 returning 来自 controller()
的承诺。因此,此时您有一个未处理的拒绝承诺。这通常是编码错误。
对于如何更正此编码错误,您有多种选择:
您可以在 .catch()
处理程序中自行处理错误,方法是调用某种错误处理函数,将错误传递给该函数并将 res
参数传递给和然后不要抛出错误。
您可以 return 来自您的 controller()
函数的承诺,然后调用该函数的任何代码都可以在那里处理被拒绝的承诺。
假设您已将您的函数绑定到
app.get('/', controller);
当 Express 调用 controller
时,它已将 100% 的控制权交给您。如果从 controller
同步抛出异常,Express 会很好,也会为您将其视为错误。但是,一旦您调用任何异步代码,您就有责任决定如何处理任何错误。
如果是 Express,您有两个选择:
- 由于您通过了
req
和 res
,您可以捕获错误并将您想要的任何响应发送回用户。
controller
实际上在 Express 中有一个 function(req, res, next)
的函数签名。这是一种很常见的格式。
如果您尚未在响应中写入任何内容,则预计将调用next
回调。如果你不带参数调用 next()
,这会告诉 Express 继续处理它拥有的 URL 处理程序集,试图找到一个可以处理请求的处理程序,returning 一个 404如果找到 none。
但是,如果您将参数传递给 next
,例如 next(err)
,Express 将跳过剩余的 URL 处理程序,而不是寻找错误处理程序。 Express 允许您注册自定义处理程序,但如果找到 none,它将 return 500。
那么你应该在你的例子中做什么?你可能想要像
这样的东西
function controller (req, res, next) {
find().then(function (result)) {
if (!result) throw new SpecificError("Couldn't find it.");
res.send("It exists!");
}).catch(next);
}
这意味着如果在 promise 链中抛出任何异常,next
函数将被调用,Express 将从那里接管。
背景
假设我正在使用 NodeJS + Express。我在 Express 中注册了某些错误处理程序,它们将以适当的方式处理我的应用程序中可能出现的所有错误。
因此,只要我需要,我就会在我的应用程序中抛出错误。如果有未处理的错误,我让它传播直到它到达错误处理程序。但是,在尝试在承诺链内部抛出错误时,我 运行 遇到了问题。举个例子:
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;
});
}
虽然我一直期待我重新抛出的错误最终至少会命中通用错误处理程序,但我却看到我发送到我的应用程序的请求挂起,以及我正在使用的承诺库抱怨 Unhandled rejection
.
问题
很简单,我想知道如何通过在我的承诺链中抛出错误来解决我似乎错误处理了我正在创建的拒绝这一事实。
编辑:为了澄清错误处理程序和 controller
函数(具体)是什么,请参阅下面的评论。
Promise 处理程序是 "throw safe"。这意味着您在任何 promise 处理程序中抛出的任何异常都将被自动捕获并变成一个被拒绝的 promise。这就是为 promise 编写规范的方式以及它们的工作方式(jQuery promises 的某些版本除外,但这只是因为它们不遵循规范)。
因此,如果您从您的 promise 库中获取 "Unhandled rejection",那将是一个有用的警告,告诉您您有一个被拒绝的 promise,但没有处理程序,因此该拒绝被默默地忽略了通常是编码错误。
而且,实际上在您的 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;
});
}
如果您到达显示 throw new SpecificError
的那一行,那么这会将承诺变成拒绝的承诺。这将导致您的 .catch()
处理程序被调用。在该处理程序中,您再次抛出,这将使承诺保持为被拒绝的承诺。因此,以 find().then(...)
开头的原始承诺现在将成为被拒绝的承诺。但是,没有更多的拒绝处理程序,您也没有 returning 来自 controller()
的承诺。因此,此时您有一个未处理的拒绝承诺。这通常是编码错误。
对于如何更正此编码错误,您有多种选择:
您可以在
.catch()
处理程序中自行处理错误,方法是调用某种错误处理函数,将错误传递给该函数并将res
参数传递给和然后不要抛出错误。您可以 return 来自您的
controller()
函数的承诺,然后调用该函数的任何代码都可以在那里处理被拒绝的承诺。
假设您已将您的函数绑定到
app.get('/', controller);
当 Express 调用 controller
时,它已将 100% 的控制权交给您。如果从 controller
同步抛出异常,Express 会很好,也会为您将其视为错误。但是,一旦您调用任何异步代码,您就有责任决定如何处理任何错误。
如果是 Express,您有两个选择:
- 由于您通过了
req
和res
,您可以捕获错误并将您想要的任何响应发送回用户。 controller
实际上在 Express 中有一个function(req, res, next)
的函数签名。这是一种很常见的格式。
如果您尚未在响应中写入任何内容,则预计将调用next
回调。如果你不带参数调用 next()
,这会告诉 Express 继续处理它拥有的 URL 处理程序集,试图找到一个可以处理请求的处理程序,returning 一个 404如果找到 none。
但是,如果您将参数传递给 next
,例如 next(err)
,Express 将跳过剩余的 URL 处理程序,而不是寻找错误处理程序。 Express 允许您注册自定义处理程序,但如果找到 none,它将 return 500。
那么你应该在你的例子中做什么?你可能想要像
这样的东西function controller (req, res, next) {
find().then(function (result)) {
if (!result) throw new SpecificError("Couldn't find it.");
res.send("It exists!");
}).catch(next);
}
这意味着如果在 promise 链中抛出任何异常,next
函数将被调用,Express 将从那里接管。