我正在编写一个API,其中我在错误处理方面遇到了一些麻烦。我不确定的是第一个代码段是否足够,或者是否应该像第二个代码段那样将它与promise混合使用。任何帮助将非常感激!
try {
var decoded = jwt.verify(req.params.token, config.keys.secret);
var user = await models.user.findById(decoded.userId);
user.active = true;
await user.save();
res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
next(error);
}
第二个代码段:
try {
var decoded = jwt.verify(req.params.token, config.keys.secret);
var user = models.user.findById(decoded.userId).then(() => {
}).catch((error) => {
});
user.active = true;
await user.save().then(() => {
}).catch((error) => {
})
res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
next(error);
}
答案 0 :(得分:0)
答案是:这取决于。
捕获每个错误
使您理解是否希望对每个错误进行不同的反应。 例如:
try {
let decoded;
try {
decoded = jwt.verify(req.params.token, config.keys.secret);
} catch (error) {
return response
.status(401)
.json({ error: 'Unauthorized..' });
}
...
但是,代码可能会变得很混乱,并且您希望对错误进行一些不同的拆分(例如:对某些 pre request 钩子进行JWT验证,并仅允许有效请求处理程序和/或在服务中执行findById
和save
部分,并在每次操作中抛出一次。
如果未找到具有给定ID的实体,则可能要抛出404。
一次捕获全部
如果您想以 a 的方式做出反应,则 a)或 b)或 c)错误,那么第一个示例就很好。
a) var decoded = jwt.verify(req.params.token, config.keys.secret);
b) var user = await models.user.findById(decoded.userId);
user.active = true;
c) await user.save();
res.status(201).json({user, 'stuff': decoded.jti});
答案 1 :(得分:0)
我阅读了一些文章,建议对每个请求都需要一个try / catch块。这有什么道理吗?
否,不是必需的。 try/catch
和await
在概念上的工作方式类似于try/catch
在常规同步异常下的工作方式。如果您只想在一个地方处理所有错误,并且希望所有代码都在一个错误处理程序中中止,无论错误发生在什么地方,也不需要捕获一个特定错误,那么您可以针对该特定错误执行一些特殊的操作,那么您只需要一个try/catch
。
但是,如果您需要专门处理一个特定的错误,甚至可能允许其余代码继续运行,那么您可能需要一个更本地的错误处理程序,可以是本地try/catch
或{{ 1}}上返回承诺的本地异步操作。
或者我是否应该像第二个代码片段中那样将它与promises混合使用。
此措辞表明您可能不太了解.catch()
的情况,因为在两个代码块中都包含了保证。
在您的两个代码块中,await
返回一个Promise。您有两种使用诺言的方法。
您可以将models.user.findById(decoded.userId);
与await
一起使用,以“暂停”该函数的内部执行,直到承诺得以解决或拒绝为止。
您可以使用.then()
或.catch()
查看承诺何时解决或拒绝。
两者都使用models.user.findById(decoded.userId);
函数调用中的承诺返回。因此,您最好这样说:“或者,如果我应该在特定的承诺上使用本地.catch()
处理程序,而不是将所有拒绝都放在一个地方。
这样做:
// skip second async operation if there's an error in the first one
async function someFunc() {
try {
let a = await someFunc():
let b = await someFunc2(a);
return b + something;
} catch(e) {
return "";
}
}
类似于最后将您的诺言与一个.catch()
处理程序链接:
// skip second async operation if there's an error in the first one
function someFunc() {
return someFunc().then(someFunc2).catch(e => "");
}
无论哪个异步函数拒绝,都将应用相同的错误处理程序。如果第一个拒绝,则第二个不执行,因为流程直接进入错误处理程序。如果在第一个异步操作中出现错误,您就是希望流通过的方式,这就是很好的条件。
但是,假设您希望将第一个函数中的错误转换为默认值,以便始终执行第二个异步操作。然后,这种控制流程将无法实现。相反,您必须在源头捕获第一个错误,以便提供默认值并继续执行第二个异步操作:
// always run second async operation, supply default value if error in the first
async function someFunc() {
let a;
try {
a = await someFunc():
} catch(e) {
a = myDefaultValue;
}
try {
let b = await someFunc2(a);
return b + something;
} catch(e) {
return "";
}
}
类似于最后将您的诺言与一个.catch()
处理程序链接:
// always run second async operation, supply default value if error in the first
function someFunc() {
return someFunc()
.catch(err => myDefaultValue)
.then(someFunc2)
.catch(e => "");
}
注意:此示例从不拒绝someFunc()
返回的承诺,而是提供默认值(此示例中为空字符串),而不是拒绝向您展示此函数中处理错误的不同方式。这当然不是必需的。在许多情况下,仅返回被拒绝的承诺是正确的选择,然后呼叫者可以决定如何处理拒绝错误。